コードからJava Swingアプリケーションを閉じる方法


94

コードからSwingアプリケーションを終了する適切な方法は何ですか?また、落とし穴は何ですか?

タイマーが作動した後、アプリケーションを自動的に閉じようとしました。しかし、を呼び出すだけdispose()ではJFrameうまくいきませんでした。ウィンドウは消えましたが、アプリケーションは終了しませんでした。ただし、閉じるボタンでウィンドウを閉じると、アプリケーションは終了します。私は何をすべきか?


タイマーのコードスニペットを投稿してください。
James Schek、2008年

回答:


106

JFrameのデフォルトの閉じるアクションは、DISPOSE_ON_CLOSE代わりに " "に設定できますEXIT_ON_CLOSE(なぜEXIT_ON_CLOSEを使い続けるのかは私を超えています)。

未処理のウィンドウまたはデーモン以外のスレッドがある場合、アプリケーションは終了しません。これはエラーと見なす必要があります(System.exitで解決することは非常に悪い考えです)。

最も一般的な原因は、java.util.Timerとユーザーが作成したカスタムスレッドです。どちらもデーモンに設定するか、明示的に強制終了する必要があります。

すべてのアクティブフレームを確認する場合は、を使用できますFrame.getFrames()。すべてのウィンドウ/フレームが破棄された場合は、デバッガーを使用して、まだ実行されているデーモン以外のスレッドを確認します。


私の場合、Swingworkerがまだアクティブであることをデバッガーで発見しました。WindowClose Eventlistenerでそのcancel(true)メソッドを呼び出すと、プログラムが終了します。ありがとう!
Hans-PeterStörr2009

各フレームでdisposeを呼び出さなければならない場合があることに注意してください。通常は「十分」です(ただし、デフォルトのクローズアクションをEXIT_ON_CLOSEに設定することも、おそらく悪い考えではありません)。
rogerdpack 2010年

あるウィンドウが別のウィンドウを開いていて、それ自体を破棄していないため、backウィンドウに使用できる場合はどうでしょうか?その後、2番目のウィンドウが閉じDISPOSE_ON_CLOSEられ、最初のウィンドウがまだ「乱されていない」ためにプログラムが終了しない場合、... 使用せずにそれを解決する方法はありDISPOSE_ON_CLOSEますか?
Svend Hansen

最初のウィンドウは自身を2番目のウィンドウのリスナーとして追加し、適切なアクションを実行する必要があります。
James Schek

3
EXIT_ON_CLOSEを使用すると、アプリケーションが強制終了されます。プログラムが終了する前にアクション(作業データの保存など)を行う必要がある場合は、通常のSwingイベントハンドラーを使用するだけでなく、JVMイベントハンドラーを利用する必要があります。どちらも「機能」しますが、EXIT_ON_CLOSEはより複雑なアプリで問題を引き起こします。
James Schek 2013年

34

EXIT_ON_CLOSEだと思います

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

before System.exit(0)は、実際にアプリを終了する前にウィンドウリスナーを作成してクリーニング操作を行うことができるため、優れています。

このウィンドウリスナーを使用すると、次のことを定義できます。

public void windowClosing(WindowEvent e) {
    displayMessage("WindowListener method called: windowClosing.");
    //A pause so user can see the message before
    //the window actually closes.
    ActionListener task = new ActionListener() {
        boolean alreadyDisposed = false;
        public void actionPerformed(ActionEvent e) {
            if (frame.isDisplayable()) {
                alreadyDisposed = true;
                frame.dispose();
            }
        }
    };
    Timer timer = new Timer(500, task); //fire every half second
    timer.setInitialDelay(2000);        //first delay 2 seconds
    timer.setRepeats(false);
    timer.start();
}

public void windowClosed(WindowEvent e) {
    //This will only be seen on standard output.
    displayMessage("WindowListener method called: windowClosed.");
}

16

試してください:

System.exit(0);

粗野ですが効果的です。


残念ながら、これは私には粗雑です。ウィンドウを閉じるイベントをいくつかのクリーンアップアクションで処理する必要があります。OK、SwingUtils.invokeLaterを使用してSystem.exitを実行することもできますが、適切な処理を行います。
Hans-PeterStörr2008年

5
System.exit(0)は単純なものではなく、悪です。すべてのフレームをチェックし、disposeを呼び出します。それが失敗する場合は、デバッガーを実行して、どの非デーモンスレッドがまだ生きているかを確認してください。
James Schek、2008年

JDK内にも、プロセスを放置する多くのバグがあります。そのため、exit()に+1しますが、デバッグビルドで無効にすることもできます。
トム・ホーティン-09

11

安全な方法は次のようなものです:

    private JButton btnExit;
    ...
    btnExit = new JButton("Quit");      
    btnExit.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e){
            Container frame = btnExit.getParent();
            do 
                frame = frame.getParent(); 
            while (!(frame instanceof JFrame));                                      
            ((JFrame) frame).dispose();
        }
    });

3
変数名にはかなり悪いスタイルFrameを正確にクラスの名前のような大文字、との...
ジャン=フィリップ・ペレット

どうもありがとうございます!これは最良の方法の1つです。
rzaaeeff 2016

9

次のプログラムには、明示的にSystem.exit()を呼び出さずに無関係なスレッドのないプログラムを終了するコードが含まれています。この例をスレッド/リスナー/タイマー/などを使用するアプリケーションに適用するには、actionPerformed()内でWindowEventが手動で開始される前に、終了を要求する(該当する場合は待機する)クリーンアップコードを挿入するだけです。

示されているとおりに実行できるコードをコピー/貼り付けたい場合は、最後に、やや醜いが関係のないメインメソッドが含まれています。

public class CloseExample extends JFrame implements ActionListener {

    private JButton turnOffButton;

    private void addStuff() {
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        turnOffButton = new JButton("Exit");
        turnOffButton.addActionListener(this);
        this.add(turnOffButton);
    }

    public void actionPerformed(ActionEvent quitEvent) {
        /* Iterate through and close all timers, threads, etc here */
        this.processWindowEvent(
                new WindowEvent(
                      this, WindowEvent.WINDOW_CLOSING));
    }

    public CloseExample() {
        super("Close Me!");
        addStuff();
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                CloseExample cTW = new CloseExample();
                cTW.setSize(200, 100);
                cTW.setLocation(300,300);
                cTW.setVisible(true);
            }
        });
    }
}

4

ユーザーが閉じるボタンをクリックしていなくても、私が正しく理解していれば、アプリケーションを閉じたいと思います。おそらく、よりニーズに合ったaddWindowListener()またはenableEvents()でWindowEventsを登録する必要があります。

その後、processWindowEvent()を呼び出してイベントを呼び出すことができます。JFrameを作成し、5秒待って、ユーザーの操作なしでJFrameを閉じるサンプルコードを次に示します。

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ClosingFrame extends JFrame implements WindowListener{

public ClosingFrame(){
    super("A Frame");
    setSize(400, 400);
            //in case the user closes the window
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setVisible(true);
            //enables Window Events on this Component
            this.addWindowListener(this);

            //start a timer
    Thread t = new Timer();
            t.start();
    }

public void windowOpened(WindowEvent e){}
public void windowClosing(WindowEvent e){}

    //the event that we are interested in
public void windowClosed(WindowEvent e){
    System.exit(0);
}

public void windowIconified(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowActivated(WindowEvent e){}
public void windowDeactivated(WindowEvent e){}

    //a simple timer 
    class Timer extends Thread{
           int time = 10;
           public void run(){
     while(time-- > 0){
       System.out.println("Still Waiting:" + time);
               try{
                 sleep(500);                     
               }catch(InterruptedException e){}
             }
             System.out.println("About to close");
    //close the frame
            ClosingFrame.this.processWindowEvent(
                 new WindowEvent(
                       ClosingFrame.this, WindowEvent.WINDOW_CLOSED));
           }
    }

    //instantiate the Frame
public static void main(String args[]){
          new ClosingFrame();
    }

}

ご覧のように、アプリケーションを閉じる前に必要な場合は、processWindowEvent()メソッドによってWindowClosedイベントが発生し、コードをクリーンアップする機会があります。


windowClosedは、System.exit(0)ではなくdispose()を呼び出す必要があります。
James Schek、2008年

2

見てくださいOracleドキュメントを

JDK 1.4以降、アプリケーションは次の場合に終了します。

  • 表示可能なAWTまたはSwingコンポーネントはありません。
  • ネイティブイベントキューにネイティブイベントはありません。
  • java EventQueuesにはAWTイベントはありません。

コーナーケース:

このドキュメントでは、一部のパッケージはリリースせずに表示可能なコンポーネントを作成することを述べています。Toolkit.getDefaultToolkit()を呼び出すプログラムは終了しません。例として挙げられているものは他にもあります。

また、他のプロセスは、何らかの理由でネイティブイベントキューにイベントを送信しているときに、AWTを存続させることができます。

また、一部のシステムでは、アプリケーションが実際に終了するまでに数秒かかることに気づきました。


0

考えは、ここにWindowListenerです-シャットダウンする前に実行したいコードをそこに追加できます


0

他のコメントに応じて、DISPOSE_ON_CLOSEはアプリケーションを適切に終了しないようです。ウィンドウを破壊するだけで、アプリケーションは実行を続けます。アプリケーションを終了する場合は、EXIT_ON_CLOSEを使用します。


この反応は、ジェームズ・シェックの答えと正反対のことを示唆しています。どちらが正しいか?(単純なアプリケーションでテストすると、どちらも機能しているようです...)
またはMapper

これをどのようにテストしたか思い出せません。
JSideris 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.