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



与ToolTipManager setDismissDelay(int毫秒)方法类似,我想在JButton上实现一个用于滚动效果的解除延迟。

在我的swing应用程序中,我为JButton设置了不同的图标(setIcon、setPressedIcon和setRolloverIcon方法),但我正在努力解决按下特定JButton时出现的问题,该按钮应该打开模式对话框。当按下按钮并显示模式对话框时,jbutton仍然显示Rollover图标,即使我将"normal"图标传递给setPressedCon方法。此外,在光标返回到主框架之前,滚动图标不会消失,如果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;
}
}

编辑

正如@camicker所建议的,我试图将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,但我希望有一个"干净"的解决方案。

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

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

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

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

编辑:

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

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

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

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

我如何使用定时器

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

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

最新更新