5

を拡張する抽象クラスを持つアプリケーションがありますJDialog。クラスを として、abstract void onClose()クラスのコンストラクターに次のコードを追加します。

addWindowListener(new WindowAdapter() {
    @Override
    public void windowClosed(WindowEvent e) {
        onClose();
    }
}

イベントは期待どおりに発生しますが、奇妙なことが起こります。このクラスの具象拡張にメソッド内で new を作成するコードがあり、これJDialogがである場合、操作を強制終了するまでイベントが継続的に発生します。onClose()JDialogdefaultCloseOperationJDialog.DISPOSE_ON_CLOSE

コードを次の SSCCE に分離しました。

// package removed
// imports removed
public class SSCCE extends JDialog {
    public static void main(String[] args) {
        SSCCE s = new SSCCE();
        s.pack();
        s.setVisible(true);
    }
    public SSCCE() {
        setLayout(new GridLayout(1, 0, 0, 0));
        JButton btn = new JButton("click me");
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                dispose();
            }
        });
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent e) {
                System.out
                        .println("SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()");
                onClose();
            }
        });
        add(btn);
    }

    public void onClose() {
        JDialog dialog = new JDialog();
        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dialog.setVisible(true);
    }

}

「クリックしてください」ボタンをクリックすると、空白JDialogSSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()表示され、コンソール ウィンドウに表示されます。空白のダイアログを閉じると、再び表示され、テキストが再び表示されます。

もう 1 つの非常に興味深い点は、初期化行を

JDialog dialog = new JDialog();

JDialog dialog = new JDialog() {
        @Override
        public synchronized void addWindowListener(WindowListener l) {
            super.addWindowListener(l);
            System.out
                    .println("SSCCE.onClose().new JDialog() {...}.addWindowListener()");
        }
    };

コンソールに次の出力が表示されます。

「クリックしてください」ボタンをクリックした場合:

SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()

ダイアログを最初に閉じるとき:

SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()

ダイアログを 2 回目に閉じると、次のようになります。

SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()
SSCCE.onClose().new JDialog() {...}.addWindowListener()

ダイアログを閉じるたびに、意図的に呼び出しているわけではありませんがaddWindowListener(WindowListener l)追加の時間が呼び出されます。

ダイアログに s を登録したくない のですが、単にメソッドをオーバーライドして呼び出しを行わないのは、ずさんすぎるWindowListenerと思います。addWindowListener(...)super.addWindowListener(...)

Mac OS X 10.6.8 で Eclipse Indigo を使用して Java 1.6.0_31 を実行しています (問題がある場合は WindowBuilder を使用)。

誰にもアイデアはありますか?

ありがとう!

4

2 に答える 2

7

Java ダイアログのチュートリアルに従って、

すべてのダイアログは Frame コンポーネントに依存しています。そのフレームが破棄されると、それに依存するダイアログも破棄されます。

引数なしで JDialog コンストラクタを使用すると、

タイトルと指定された Frame 所有者のないモードレス ダイアログを作成します。共有の非表示フレームがダイアログの所有者として設定されます。

その共有隠しフレームはSwingUtilities$SharedOwnerFrameであり、初期化時にWindowListener所有するすべてのウィンドウに を登録します。

ダイアログを閉じると、SharedOwnerFramewindowClosedメソッドが呼び出され、それが所有するすべてのウィンドウ (この時点では元の SSCCE ダイアログと新しいダイアログ) がチェックされ、何も表示されていないことがわかり、それ自体が破棄されます。これには、所有するすべてのダイアログを破棄するという影響があり、それぞれにウィンドウ クローズ イベントがポストされます。これによりリスナーが呼び出さwindowClosedれ、新しいダイアログが開きます。そして、また行きます:-)。SharedOwnerFrame最後のコメントに関しては、所有するダイアログごとに 1 つ取得するため、毎回追加のログ行を取得します。

SSCCE ダイアログが新しいダイアログを (そのコンストラクターに渡すことによって)所有thisするようにすると、所有権が共有されることはなく、正常に動作します。

 public void onClose() {
     JDialog dialog = new JDialog(this);
     dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
     dialog.setVisible(true);
 }
于 2012-04-20T00:05:33.317 に答える
4
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;

public class SSCCE extends JDialog {
    public static void main(String[] args) {
        SSCCE s = new SSCCE();
        s.pack();
        s.setVisible(true);
    }

    private WindowAdapter wa = new WindowAdapter() {
        @Override
        public void windowClosed(WindowEvent e) {
            System.out
                    .println("SSCCE.SSCCE().new WindowAdapter() {...}.windowClosed()");
            onClose();
        } 
    };

    public SSCCE() {
        setLayout(new GridLayout(1, 0, 0, 0));
        JButton btn = new JButton("click me");
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                dispose();
            }
        });
        addWindowListener(
        wa);
        add(btn);
    }

    public void onClose() {
        removeWindowListener(wa);
        JDialog dialog = new JDialog();
        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dialog.setVisible(true);

    }

}
于 2012-04-19T21:42:21.357 に答える