Java 如何在Swing中临时禁用事件侦听器?
我有一个带有模型和视图的Swing应用程序。在视图(GUI)中有许多组件,每个组件都映射到模型对象的某些属性并显示其值 现在有一些UI组件,当某些模型属性的值在UI中更改时,它们会自动触发更新。这需要我在UI中重新加载完整的模型。这样我就进入了一个无限更新循环,因为UI中的每个模型重新加载都会触发另一个模型重新加载 我有一个指示加载过程的标志,我想用它暂时抑制侦听器通知,同时从模型中设置UI字段。所以我的问题是:Java 如何在Swing中临时禁用事件侦听器?,java,events,swing,event-dispatching,Java,Events,Swing,Event Dispatching,我有一个带有模型和视图的Swing应用程序。在视图(GUI)中有许多组件,每个组件都映射到模型对象的某些属性并显示其值 现在有一些UI组件,当某些模型属性的值在UI中更改时,它们会自动触发更新。这需要我在UI中重新加载完整的模型。这样我就进入了一个无限更新循环,因为UI中的每个模型重新加载都会触发另一个模型重新加载 我有一个指示加载过程的标志,我想用它暂时抑制侦听器通知,同时从模型中设置UI字段。所以我的问题是: 是否有一种方法可以在Swing中全局临时禁用某些组件的侦听器,而无需删除和重新连接
是否有一种方法可以在Swing中全局临时禁用某些组件的侦听器,而无需删除和重新连接它们?您可以为侦听器使用一个公共基类,其中有一个静态方法来打开或关闭侦听器:
public abstract class BaseMouseListener implements ActionListener{
private static boolean active = true;
public static void setActive(boolean active){
BaseMouseListener.active = active;
}
protected abstract void doPerformAction(ActionEvent e);
@Override
public final void actionPerformed(ActionEvent e){
if(active){
doPerformAction(e);
}
}
}
监听器必须实现doPerformAction()
,而不是actionPerformed()
(这在企业场景中会很糟糕,但在Swing这样的单一VM模型中,它应该可以正常工作)通常我使用一个标志指示API更改或用户更改。对于每个侦听器,我将检查标志,如果它的API发生了更改,则返回。一个可能适用于您的选项是在加载时放置一个玻璃窗格,以便在加载期间阻止事件: 看起来是一个类似的问题,没有令人满意的解决方案 我发现这有助于批判性地检查我自己的设计 有没有一种方法可以在Swing中全局临时禁用某些组件的侦听器,而不删除并重新连接它们
每个
JComponent
都维护一个可供子类访问的。如果需要,您可以始终直接对列表进行操作,或者将所需的行为构建到自定义的实现中。在搜索stackoverflow时,我发现了这个问题。我想补充一下我的意见/答案
在Swing中暂时禁用事件侦听器确实是个坏主意。如果您的代码被破坏(或者出现了其他错误),您可能无法使应用程序恢复生命—响应用户和其他事件
如果您想放弃(响应但不执行任何操作)用户事件,您可以使用可以忽略事件的玻璃窗格
如果您的EDT正忙(您必须再次尽可能避免),并且您希望在该时间段内放弃用户操作,您仍然可以使用glasspane并在所有事件响应(glasspane忽略)后使用invokeLater将其删除,以删除窗格
包括SSCE在内的全部详细信息可在此问题中找到
如上所述,玻璃材质窗格玻璃在这方面很有帮助。 下面是一个简单的例子:
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.SwingWorker;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GlassPaneExample extends JFrame implements ActionListener {
private JButton btnDisable;
private JButton btnTestOne;
private JButton btnTestTwo;
private MyGlassPane glass;
private boolean actionAllowed = true;
public GlassPaneExample() {
// init JFrame graphics
setBounds(300, 300, 300, 110);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setVisible(true);
// init buttons
btnTestOne = new JButton("Button one");
add(btnTestOne);
btnTestTwo = new JButton("Button two");
add(btnTestTwo);
btnDisable = new JButton("Disable ActionListeners for 2 seconds");
add(btnDisable);
// create Glass pane
glass = new MyGlassPane();
setGlassPane(glass);
// add listeners
btnTestOne.addActionListener(this);
btnTestTwo.addActionListener(this);
btnDisable.addActionListener(this);
}
public static void main(String[] args) {
new GlassPaneExample();
}
@Override
public void actionPerformed(ActionEvent e) {
JButton src = (JButton)e.getSource();
if (src.equals(btnDisable)) {
// setting glasspane visibility to 'true' allows it to receive mouse events
glass.setVisible(true);
setCursor(new Cursor(Cursor.WAIT_CURSOR));
SwingWorker sw = new SwingWorker() {
@Override
protected Object doInBackground()
throws Exception {
Thread.sleep(2000);
return null;
}
@Override
public void done() {
// set cursor and GlassPane back to default state
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
glass.setVisible(false);
// allow actions to be received again
actionAllowed = true;
}
};
sw.execute();
} else if (actionAllowed) {
if (src.equals(btnTestOne)) {
JOptionPane.showMessageDialog(this, "BUTTON ONE PRESSED");
} else if (src.equals(btnTestTwo)) {
JOptionPane.showMessageDialog(this, "BUTTON TWO PRESSED");
}
}
}
class MyGlassPane extends JPanel {
public MyGlassPane() {
setOpaque(false);
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
actionAllowed = false;
}
});
}
//Draw an cross to indicate glasspane visibility
public void paintComponent(Graphics g) {
g.setColor(Color.red);
g.drawLine(0, 0, getWidth(), getHeight());
g.drawLine(getWidth(), 0, 0, getHeight());
}
}
}另请参见感谢链接!看起来是一个类似的问题,没有令人满意的解决方案。