java - 如何设置JButton的翻转效果的关闭延迟?

标签 java swing jbutton rollover

类推 ToolTipManager setDismissDelay(int milliseconds) 方法,我想为 JButton 上的翻转效果实现解除延迟。

在我的 swing 应用程序中,我为 JButton 设置了不同的图标(setIcon、setPressedIcon 和 setRolloverIcon 方法),但我试图解决按下应打开模式对话框的特定 JButton 时发生的问题。 当按下按钮并显示模式对话框时,即使我将“普通”图标传递给 setPressedIcon 方法,jbutton 仍然显示翻转图标。 此外,鼠标悬停图标不会消失,直到光标返回主框架,即使 jdialog 已关闭。

我举了一个例子来说明我的意思。我只在主框架中放置了两个按钮,每个按钮都有一个绿色方形图标作为“正常”图标,以及一个用于翻转效果的红色图标。 正如我所说,我希望按钮在按下时再次显示绿色图标。第一个按钮的行为将“错误”,因为红色图标在 jdialog 创建后可见。 对于第二个按钮,我通过在按下按钮时调用 setRollover (false) 覆盖 isPressed () 方法(在其 DefaultButtonModel 中)解决了这个问题。

我认为这不是最好的解决方案,我不想直接对 ButtonModel 进行操作。 所以我想知道您是否有更好的想法,也许类似于 setDismissDelay 方法,正如我之前所说。谢谢!

这里有一个 SSCE:

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.DefaultButtonModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SSCE
{
    public static void main (String[] a) {
        SwingUtilities.invokeLater (new Runnable () {
            public void run () {
                JFrame frame = new JFrame ("Icon Test");
                frame.setContentPane (new MainPanel (frame));
                frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
                frame.setResizable (false);
                frame.pack ();
                frame.setLocationRelativeTo (null);
                frame.setVisible (true);
            }
        });
    }
}
class MainPanel extends JPanel
{
    public MainPanel (JFrame parent) {
        JButton firstButton = createButton (createButtonImage (Color.GREEN), createButtonImage (Color.RED), parent);
        JButton secondButton = createButton (createButtonImage (Color.GREEN), createButtonImage (Color.RED), parent);
        secondButton.setModel (new DefaultButtonModel () {
            @Override public boolean isPressed () {
                boolean isPressed = super.isPressed ();
                if (isPressed) setRollover (false);
                return isPressed;
            }
        });
        add (firstButton);
        add (secondButton);
    }
    private JButton createButton (BufferedImage normalImage, BufferedImage rolloverImage, final JFrame parent) {
        ImageIcon normalIcon = new ImageIcon (normalImage), rolloverIcon = new ImageIcon (rolloverImage);
        JButton button = new JButton (new AbstractAction () {
            public void actionPerformed (ActionEvent e) {
                JDialog dialog = new JDialog (parent, "Test Dialog",true);
                dialog.setSize (400, 400);
                dialog.setLocationRelativeTo (parent);
                dialog.setVisible (true);
            }
        });
        button.setBorderPainted (false);
        button.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR));
        button.setFocusPainted (false);
        button.setContentAreaFilled (false);
        button.setIcon (normalIcon);    
        button.setPressedIcon (normalIcon);
        button.setRolloverEnabled (true);
        button.setRolloverIcon (rolloverIcon);
        return button;
    }
    private BufferedImage createButtonImage (Color color) {
        BufferedImage image = new BufferedImage (20, 20, BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics ();
        g.setColor (color);
        g.fillRect (0, 0, 20, 20);
        g.dispose ();
        return image;
    }
}

编辑:

正如 @camickr 所建议的,我尝试将 ActionListener 代码包装在 SwingUtilities.invokeLater () 中。

我不会重新发布完整的代码,我只替换了这些行:

JButton button = new JButton (new AbstractAction () {
                public void actionPerformed (ActionEvent e) {
                    JDialog dialog = new JDialog (parent, "Test Dialog",true);
                    dialog.setSize (400, 400);
                    dialog.setLocationRelativeTo (parent);
                    dialog.setVisible (true);
                }
            });

与:

JButton button = new JButton ();
    button.addActionListener (new ActionListener () {
            public void actionPerformed (ActionEvent e) {
                SwingUtilities.invokeLater (new Runnable () {
                    public void run () {
                        JDialog dialog = new JDialog (parent, "Test Dialog",true);
                        dialog.setSize (400, 400);
                        dialog.setLocationRelativeTo (parent);
                        dialog.setVisible (true);
                    }
                });
            }
        });

但是,这并不能解决我的问题,创建对话框时红色图标仍然可见。 我尝试了一些小的调整,使用 addActionListener 或 setAction,也只在 invokeLater 调用中调用 setVisible,但它仍然不起作用。

另外,如果不在我现在使用的 ButtonModel 上使用相同的代码,我如何使用计时器? 我已经尝试了一些“黑客”,通过在 actionPerformed 中设置“正常图标”,然后使用“自定义”ActionEvent 调用另一个 Action,但我希望有一个“干净”的解决方案。

最佳答案

监听器中的所有代码都在事件调度线程 (EDT) 上执行。

问题是在调用 ActionListener 代码之前按钮的状态没有更改。一旦显示模式对话框,按钮状态更改代码将不会执行,直到对话框关闭。

ActionListener 中的代码包装在 SwingUtilities.invokeLater() 中。此代码将添加到 EDT 的末尾,以便在显示对话框之前完成正常的按钮处理。

阅读 Swing 教程中有关 Swing 并发性的部分,了解有关 EDT 的更多信息。

编辑:

i would prefer not to act directly on ButtonModel

花更多时间玩代码。问题在于,显示对话框时不会生成 mouseExited ,因此 ButtonModel 的状态永远不会更新。

另一个选项可能是为 mouseExited 事件手动生成 MouseEvent 并在显示对话框之前将该事件分派(dispatch)给按钮。

尽管这种方法也被认为是一种黑客行为。

how could i use a Timer

同样,问题在于按钮的状态。即使您使用计时器,您也需要手动重置模型的状态。

您当前的解决方案似乎是合理的,因为所有逻辑都位于自定义行为的类中。

关于java - 如何设置JButton的翻转效果的关闭延迟?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41830545/

相关文章:

java - 当超出 "short"范围时会发生什么?

java - 尝试让 Selenium Chrome 驱动程序刷新页面直到找到项目,但所有方法都失败

java - 有没有办法向 Hibernate 传递一个填充了任何字段的对象(通用),并让它返回填充了所有字段的对象列表?

java - 改变jframe的亮度

java - 如何实际选择一个 JButton

java - 启用/禁用与某些方法关联的 JButton

java - 创建没有现有类的对象

java - 如何在 BoxLayout 中使组件全宽

java - 使用 JFrame 的浏览器

java - JButton 单击时会在文本周围留下一些边框