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

Java-在JButton悬停中添加和删除带下划线的文本,java,swing,mouseevent,jbutton,Java,Swing,Mouseevent,Jbutton,我使用以下代码成功地在用户将鼠标悬停在JButton上时产生带下划线文本的悬停效果。这是工作的预期 单击时,JButton会从屏幕上删除当前的JPanel,并向其中添加一个新的JPanel。这也行得通 问题是,当实际单击时,带下划线文本的悬停效果将永久保留在JButton上,并且在移动鼠标时不会消失 我尝试实现mouseClicked()以使其在单击按钮时删除带下划线的效果,但这没有效果。我可以使用一些专家的建议来保持下划线效果,同时在通过action listener添加新的JPanel时删除

我使用以下代码成功地在用户将鼠标悬停在JButton上时产生带下划线文本的悬停效果。这是工作的预期

单击时,JButton会从屏幕上删除当前的JPanel,并向其中添加一个新的JPanel。这也行得通

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

我尝试实现
mouseClicked()
以使其在单击按钮时删除带下划线的效果,但这没有效果。我可以使用一些专家的建议来保持下划线效果,同时在通过action listener添加新的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);
});
但这有点“笨拙”,因为它从模型侦听器中更改按钮的状态

我可以使用一些专家的建议来保持下划线效果,同时在通过action listener添加新的JPanel时删除它

为什么要通过ActionListener删除它?按钮仍处于活动状态。用户没有理由不能再次单击按钮

在任何情况下,您的原始逻辑都是合理的,您只需要删除
mouseExited
和/或
mouseClicked
事件中的underline属性。你应该从气垫船的答案中学到的关键部分是如何从字体中删除
下划线
属性

我想在多个按钮上重复使用它,而无需重复代码

如果您遵循自己的原始解决方案,则可以共享
鼠标侦听器
,因为事件的来源将是按钮:

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

考虑使用按钮<代码> ButoMutux而不是<代码> MouseListener < /Cord> @ MyDealthRealver:我自己也在考虑这样的解决方案,但是我认为模型很难获得对使用它的对象的引用,因为许多这样的对象可以使用同一个模型对象,并且该模型没有<代码> GETSoCube()。或与之相关的类似方法。好的,我解决了它,但使用了kludge@HovercraftFullOfEels是的,你可能需要某种“控制器”,你可以将信息传递给它,这不是一个令人愉快的主意,但它确实涵盖了鼠标和键盘操作:太棒了!这确实解决了问题,一旦鼠标侦听器被删除。只要行得通,我不介意胡闹哈哈。如果您不介意的话,在它自己的命名类中,而不是作为一个匿名的内部类,这会是什么样子?我想在多个按钮上重复使用它,而无需重复代码。