如何设置JButton翻转效果的解雇延迟?

时间:2017-01-24 14:20:26

标签: java swing jbutton rollover

通过类比ToolTipManager setDismissDelay(int milliseconds)方法,我想对JButton上的翻转效果实现一个消除延迟。

在我的swing应用程序中,我为我的JButtons设置了不同的图标(setIcon,setPressedIcon和setRolloverIcon方法),但是我试图解决当应该打开模态对话框的特定JButton被按下时出现的问题。 当按下按钮并显示模态对话框时,即使我通过"正常"按钮仍然显示翻转图标。图标到setPressedIcon方法。 此外,翻转图标不会消失,直到光标返回到主框架,如果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);
                }
            });

with:

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? 我已经尝试了一些" hacks"通过设置"正常图标"在actionPerformed中,然后使用" custom"调用另一个Action。 ActionEvent,但我希望有一个" clean"溶液

1 个答案:

答案 0 :(得分:2)

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

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

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

有关EDT的详细信息,请阅读Swing中Swutch并行教程中的部分。

编辑:

  

我不想直接在ButtonModel上行动

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

另一种选择可能是为MouseEvent事件手动生成mouseExited,并在显示对话框之前将事件发送到按钮。

虽然这种方法也被视为黑客攻击。

  

我怎么能使用计时器

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

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