通过类似于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
并将该事件分派给按钮,然后显示对话框。
虽然这种方法也被认为是骇客。
我如何使用计时器
同样,问题出在按钮的状态。即使使用计时器,您也需要手动重置模型状态。
您的当前解决方案似乎是合理的,因为所有逻辑都位于可自定义行为的类中。