Justiciar
Justiciar

Reputation: 376

Java - Adding and removing underlined text in a JButton on Hover

I am using the following code to successfully have a hover effect of underlined text when the user mouses over a JButton. This is working as intended.

When clicked, the JButton simply removes the current JPanel from the screen, and adds a new one to it. This also works.

The problem is that when actually clicked, the hover effect of underlined text remains permanently on the JButton and does not go away when the mouse is moved.

I tried implementing mouseClicked() to have it remove the underlined effect when the button is clicked but this has no effect. I could use some expert advice on how to keep the underlining effect in place, while removing it when the new JPanel is added through an action listener.

Snippet:

class MyAcctListener implements ActionListener
{
    public void actionPerformed(ActionEvent e) 
    {
        totalGUI.removeAll();
        totalGUI.add(headerPanel, BorderLayout.NORTH);
        totalGUI.add(myAcctPanel, BorderLayout.CENTER);
        repaint();
        revalidate();
    }
}

@SuppressWarnings("unchecked")
class HeaderMouseListener extends MouseAdapter
{
    Font original;

    @Override
    public void mouseEntered(MouseEvent evt) {
        original = evt.getComponent().getFont();
        Map attributes = original. getAttributes();
        attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
        evt.getComponent().setFont(original.deriveFont(attributes));
    }

    @Override
    public void mouseExited(MouseEvent evt){
        evt.getComponent().setFont(original);   
    }

    @Override
    public void mouseClicked(MouseEvent evt) {
        evt.getComponent().setFont(original); 
    }
}


private void createComponents() {
    MouseListener headerMouseListener = new HeaderMouseListener();
    acctButton = new JButton("My Account");
    acctButton.setFont(buttonFont);
    acctButton.setForeground(Color.BLUE);
    acctButton.setBorderPainted(false);
    acctButton.setContentAreaFilled(false);
    acctButton.addMouseListener(headerMouseListener);
    ActionListener myacctListener = new MyAcctListener();
    acctButton.addActionListener(myacctListener);
}

Upvotes: 0

Views: 1941

Answers (2)

camickr
camickr

Reputation: 324157

I could use some expert advice on how to keep the underlining effect in place, while removing it when the new JPanel is added through an action listener

Why would you remove it via the ActionListener? The button is still active. There is no reason the user couldn't click on the button again.

In any case your original logic is reasonable you just need to remove the underline attribute in the mouseExited and/or mouseClicked events. The key part you should have learned from Hovercraft's answer was how to remove the underline attribute from the font.

I'd like to reuse it on multiple buttons without repeating code.

If you follow your own original solution then you can share the MouseListener because the source of the event will be the button:

MouseListener ml = new MouseAdapter()
{
    @Override
    public void mouseEntered(MouseEvent evt) {
        Component button = evt.getComponent();
        Font font = button.getFont();
        Map attributes = font.getAttributes();
        attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
        button.setFont(font.deriveFont(attributes));
    }

    @Override
    public void mouseExited(MouseEvent evt){
    System.out.println("Exited");
        Component button = evt.getComponent();
        Font font = button.getFont();
        Map attributes = font.getAttributes();
        attributes.put(TextAttribute.UNDERLINE, null);
        button.setFont(font.deriveFont(attributes));
    }
    /*
    @Override
    public void mouseClicked(MouseEvent evt) {
        Component button = evt.getComponent();
        Font font = button.getFont();
        Map attributes = font.getAttributes();
        attributes.put(TextAttribute.UNDERLINE, null);
        button.setFont(font.deriveFont(attributes));
    }
    */
};

JButton button1 = new JButton("Button 1");
add( button1 );
button1.addMouseListener( ml );

JButton button2 = new JButton("Button 2");
add( button2 );
button2.addMouseListener( ml );

Upvotes: 0

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

As per MadProgrammer's suggestion, one possible solution is to add a ChangeListener to the button's model, and check for model.isRollover() within that listener and behave accordingly.

For example:

button.getModel().addChangeListener(evt -> {
    ButtonModel model = (ButtonModel) evt.getSource();
    Font btnFont = button.getFont();
    Map attributes = btnFont.getAttributes();

    if (model.isRollover()) {
        attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
    } else {
        attributes.put(TextAttribute.UNDERLINE, null);
    }
    btnFont = btnFont.deriveFont(attributes);
    button.setFont(btnFont);
});

But this is somewhat "kludgy" as it changes the state of the button from within its model listener.

Upvotes: 1

Related Questions