14

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

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

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

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

4

6 回答 6

8

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

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

于 2011-01-18T10:20:23.613 回答
4

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

于 2011-01-18T10:22:32.580 回答
4

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

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

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

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

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

java等待光标显示问题

于 2012-05-18T15:15:32.047 回答
3

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

于 2011-01-18T12:46:45.057 回答
3

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

}

于 2012-12-03T09:27:43.000 回答
2

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

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

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

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

于 2011-01-18T13:48:58.757 回答