Java - 在悬停时在 JButton 中添加和删除带下划线的文本

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

当用户将鼠标悬停在 JButton 上时,我使用以下代码成功实现了带下划线文本的悬停效果。这是按预期工作的。

单击时,JButton 只是从屏幕上删除当前的 JPanel,并向其中添加一个新的 JPanel。这也有效。

问题是在实际点击时,下划线文本的悬停效果永久保留在 JButton 上,并且在移动鼠标时不会消失。

我尝试实现 mouseClicked() 以使其在单击按钮时删除下划线效果,但这没有效果。关于如何保持下划线效果,同时在通过动作侦听器添加新的 JPanel 时将其删除,我可以使用一些专家建议。

片段:

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);
}

根据 MadProgrammer 的建议,一种可能的解决方案是将 ChangeListener 添加到按钮的模型中,并在该侦听器中检查 model.isRollover() 并相应地进行操作。

例如:

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);
});

但这有点 "kludgy" 因为它从其模型侦听器中更改了按钮的状态。

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

为什么要通过 ActionListener 删除它?该按钮仍然有效。用户没有理由不能再次点击按钮。

无论如何你原来的逻辑是合理的你只需要删除 mouseExited and/or mouseClicked 事件中的下划线属性。您应该从 Hovercraft 的回答中学到的关键部分是如何从字体中删除 underline 属性。

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

如果您遵循自己的原始解决方案,那么您可以分享 MouseListener 因为事件的来源将是按钮:

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 );