通过类似于ToolTipManager setDismissDelay(int milliseconds)方法,我想为JButton上的翻转效果实现关闭延迟。

在我的swing应用程序中,我为JButton设置了不同的图标(setIcon,setPressedIcon和setRolloverIcon方法),但是我试图解决按下特定JButton(应打开模式对话框)时发生的问题。
当按下按钮并显示模式对话框时,即使我将“ normal”图标传递给setPressedIcon方法,jbutton仍显示Rollover图标。
此外,如果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进行一些小的调整,也仅将setVisible调用到invokeLater调用中,但仍然无法正常工作。

另外,如何在不使用现在使用的ButtonModel上使用相同代码的情况下使用Timer?
我已经通过在actionPerformed内设置“正常图标”,然后使用“自定义” ActionEvent调用另一个Action来尝试一些“ hacks”,但是我想拥有一个“干净”的解决方案。

最佳答案

侦听器中的所有代码都在Event Dispatch Thread (EDT)上执行。

问题在于,在调用ActionListener代码之前,按钮的状态不会更改。显示模式对话框后,在关闭对话框之前,不会执行按钮状态更改代码。

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

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

编辑:


  我宁愿不要直接对ButtonModel采取行动


花更多时间玩代码。问题是显示对话框时没有生成mouseExited,因此ButtonModel的状态从不更新。

另一个选择是为MouseEvent事件手动生成一个mouseExited并将该事件分派给按钮,然后显示对话框。

虽然这种方法也被认为是骇客。


  我如何使用计时器


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

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

10-08 00:46