如何在Swing中暂时禁用事件监听器?

我有一个带有模型和视图的Swing应用程序。 在视图(GUI)中有许多组件,每个组件都映射到模型对象的某些属性并显示它的值。

现在有一些UI组件会在UI中的值发生更改时自动触发某些模型属性的更新。 这需要我在UI中重新加载完整的模型。 这样我就进入了一个无限的更新循环,因为UI中的每个模型重新加载都会触发另一个模型重新加载。

我有一个标志指示加载过程,我想用它来暂时禁止监听器通知,同时从模型中设置UI字段。 所以我的问题是:

有没有办法在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更改,则返回。

在搜索stackoverflow时,我发现了这个问题。 我想加上我的意见/答案。

暂时禁用 Swing中的事件侦听器实属上是个坏主意。 如果您的代码被破坏(或出现其他问题),您可能无法恢复您的应用程序 – 响应用户和其他事件。

如果要丢弃(响应但不执行任何操作)用户事件,则可以使用可忽略事件的玻璃窗格。

如果您的EDT繁忙(您必须尽可能地避免)并且您想要放弃该时段的用户操作,您仍然可以使用glasspane并使用invokeLater将其删除以在所有事件都已响应后删除窗格(被玻璃窗忽视了。

在这个问题中可以找到包括SSCE在内的完整详细信息。

java等待光标显示问题

可能对您有用的一个选项就是在加载时放置一个玻璃窗格,以便在此期间阻止事件: http : //download.oracle.com/javase/tutorial/uiswing/components/rootpane.html#glasspane

如上所述,GlassPane在这方面很有帮助。 这是一个简单的例子:

 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()); } } 

}

这个问题看起来像一个类似的问题,没有令人满意的解决方案。

我发现这篇文章有助于批判性地检查我自己的设计。

有没有办法在Swing中全局暂时禁用某些组件的侦听器而无需删除并重新附加它们?

每个JComponent维护一个EventListenerList ,您的子类可以访问它。 如有必要,您可以始终直接在列表上操作,或者在EventListener自定义实现中构建所需的行为