【问题标题】:How to temporarily disable event listeners in Swing?如何在 Swing 中临时禁用事件监听器?
【发布时间】:2011-06-11 00:07:46
【问题描述】:

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

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

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

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

【问题讨论】:

标签: java events swing event-dispatching


【解决方案1】:

您可以为您的侦听器使用一个公共基类,并在其中有一个静态方法来打开或关闭侦听器:

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 模型中,它应该可以正常工作)

【讨论】:

    【解决方案2】:

    通常我使用一个标志来指示 API 更改或用户更改。对于每个侦听器,我会检查标志,如果它的 API 更改则返回。

    【讨论】:

      【解决方案3】:

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

      在 Swing 中临时禁用事件侦听器确实是个坏主意。如果您的代码损坏(或其他问题),您可能无法使您的应用程序恢复活力 - 响应用户和其他事件。

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

      如果您的 EDT 很忙(同样您必须尽可能避免这种情况)并且您想放弃该期间的用户操作,您仍然可以使用玻璃窗格并使用 invokeLater 将其删除,以便在所有事件发生后移除窗格已响应(被玻璃板忽略)。

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

      java wait cursor display problem

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

          如上所述,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());
             }
          }
          

          }

          【讨论】:

            【解决方案6】:

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

            我发现这个article 有助于批判性地检查我自己的设计。

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2016-10-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多