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

あなたのために働くかもしれない1つのオプションは、ロード中にガラスのペインを上げて、その間のイベントをブロックすることです: 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 で一部のコンポーネントのリスナーを削除して再接続せずにグローバルに一時的に無効にする方法はありますか?

Everyは、サブクラスからアクセスできる をJComponent維持します。EventListenerList必要に応じて、いつでもリストを直接操作したり、目的の動作をカスタム実装に組み込んだりできます。EventListener

于 2011-01-18T13:48:58.757 に答える