Java Swing uygulaması koddan nasıl kapatılır


94

Bir Swing uygulamasını koddan sonlandırmanın doğru yolu nedir ve tuzaklar nelerdir?

Bir zamanlayıcı devreye girdikten sonra uygulamamı otomatik olarak kapatmaya çalıştım. Ama sadece çağıran dispose()üzerinde JFramehile yapmadım - pencere kayboldu ancak uygulama sona etmedi. Ancak pencereyi kapat butonu ile kapatırken uygulama sona erer. Ne yapmalıyım?


Lütfen zamanlayıcınızın kod parçacığını gönderin.
James Schek

Yanıtlar:


106

JFrame varsayılan kapatma işleminiz DISPOSE_ON_CLOSEyerine " " olarak ayarlanabilir EXIT_ON_CLOSE(insanların neden EXIT_ON_CLOSE kullanmaya devam etmeleri beni aşıyor).

Kullanılmamış herhangi bir pencereniz veya arka plan programı olmayan iş parçacıklarınız varsa, uygulamanız sona ermez. Bu bir hata olarak görülmelidir (ve System.exit ile çözmek çok kötü bir fikirdir).

En yaygın suçlular java.util.Timer ve oluşturduğunuz özel bir İş Parçacığıdır. Her ikisi de arka plan programına ayarlanmalı veya açıkça öldürülmelidir.

Tüm aktif çerçeveleri kontrol etmek istiyorsanız, kullanabilirsiniz Frame.getFrames(). Tüm Windows / Çerçeveler atılırsa, hala çalışmakta olan arka plan programı olmayan iş parçacıklarını kontrol etmek için bir hata ayıklayıcı kullanın.


Benim durumumda, hata ayıklayıcı ile hala aktif bir Swingworker'ım olduğunu keşfettim. WindowClose Eventlistener'da cancel (true) yöntemini çağırdım ve program şimdi sona eriyor. Teşekkürler!
Hans-Peter Störr

Her çerçevede dispose çağırmanız gerekebileceğini ve bu genellikle "yeterli" olduğunu unutmayın (ancak varsayılan kapatma eylemini EXIT_ON_CLOSE olarak ayarlamak da muhtemelen kötü bir fikir değildir).
rogerdpack

Ya bir pencereniz diğerini açıyorsa, ancak kendisini bir backpencere olarak kullanabilmek için kendini elden çıkarmıyorsa ? İkinci pencere kapatılır ve kullanmak ise DISPOSE_ON_CLOSEilk penceresi hala "gönülsüz" olduğu için programı sonlandırmaz ... bu çözmek için bir yol yoktur olmadan kullanan DISPOSE_ON_CLOSE?
Svend Hansen

İlk pencere kendisini ikinci pencereye dinleyici olarak eklemeli ve uygun işlemi yapmalıdır.
James Schek

3
EXIT_ON_CLOSE'u kullanmak, uygulamayı zorla sonlandırır. Program çıkmadan önce harekete geçmeniz gerekiyorsa (çalışma verilerini kaydetmek gibi), sadece normal swing olay işleyicilerini kullanmak yerine JVM olay işleyicilerine dokunmanız gerekir. Her ikisi de "çalışacak", ancak EXIT_ON_CLOSE daha karmaşık uygulamalarda sorunlara neden olacaktır.
James Schek

34

Sanırım bir EXIT_ON_CLOSE

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

uygulamadan çıkmadan önce bazı temizleme işlemleri yapmak için System.exit(0)bir Pencere Dinleyicisi yazabileceğinizden, daha önce daha iyidir .

Bu pencere dinleyicisi şunları tanımlamanıza izin verir:

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

Deneyin:

System.exit(0);

Kaba ama etkili.


Maalesef bu benim için çok kaba. Bazı temizleme eylemleri için pencere kapatma olaylarının işlenmesini istiyorum. Tamam, bir SwingUtils.invokeLater ile System.exit yapabilirim, ancak doğru olanı yapmayı tercih ederim.
Hans-Peter Störr

5
System.exit (0) sadece kaba değil, kötüdür. Tüm çerçeveleri kontrol edin, dispose'u arayın. Bu başarısız olursa, bir hata ayıklayıcı çalıştırın ve hangi arka plan programı olmayan iş parçacıklarının hala hayatta olduğunu görün.
James Schek

JDK'da bile süreci terk eden birçok hata var. Yani +1 çıkmak için (), ancak hata ayıklama yapılarında devre dışı bırakmak isteyebilirsiniz.
Tom Hawtin - tackline

11

Belki güvenli yol şuna benzer bir şeydir:

    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
Bir değişkeni Framebüyük harfle adlandırmak oldukça kötü bir tarz , tıpkı bir sınıfın adı gibi ...
Jean-Philippe Pellet

Çok teşekkür ederim! Bu en iyi yollardan biridir!
rzaaeeff

9

Aşağıdaki program, açıkça System.exit () 'i çağırmadan dıştan iş parçacıkları içermeyen bir programı sonlandıracak kodu içerir. Bu örneği iş parçacıkları / dinleyiciler / zamanlayıcılar / vb. Kullanan uygulamalara uygulamak için, yalnızca WindowEvent actionPerformed () içinde manuel olarak başlatılmadan önce temizlik kodunu isteyen (ve uygunsa, sonlandırmayı bekleyen) girilmesi gerekir.

Tam olarak gösterildiği gibi çalışabilen kodu kopyalamak / yapıştırmak isteyenler için, sonunda biraz çirkin ama başka türlü ilgisiz bir ana yöntem yer almaktadır.

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

Sizi doğru anladıysam, kullanıcı kapat düğmesine tıklamasa bile uygulamayı kapatmak istersiniz. WindowEvents'i belki addWindowListener () veya enableEvents () ile ihtiyaçlarınıza daha uygun olanı kaydetmeniz gerekir.

Daha sonra olayı processWindowEvent () çağrısıyla çağırabilirsiniz. İşte bir JFrame oluşturacak, 5 saniye bekleyecek ve JFrame'i kullanıcı etkileşimi olmadan kapatacak örnek bir kod.

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();
    }

}

Gördüğünüz gibi, processWindowEvent () yöntemi, uygulamayı kapatmadan önce gerekirse bazı temizleme kodu yapma fırsatınız olduğunda WindowClosed olayının tetiklenmesine neden olur.


windowClosed, System.exit (0) değil dispose () çağırmalıdır.
James Schek

2

Oracle Dokümantasyonuna bir göz atın .

JDK 1.4'ten başlayarak bir Uygulama aşağıdaki durumlarda sona erer:

  • Görüntülenebilir AWT veya Swing bileşenleri yoktur.
  • Yerel olay kuyruğunda yerel olay yoktur.
  • Java EventQueues'de AWT olayı yoktur.

Köşeler:

Belge, bazı paketlerin serbest bırakmadan görüntülenebilir bileşenler oluşturduğunu belirtir. Toolkit.getDefaultToolkit () 'i çağıran bir program sona ermeyecektir. örnek olarak verilen diğerleri arasındadır.

Ayrıca diğer Süreçler, her ne sebeple olursa olsun yerel olay kuyruğuna olay gönderirken AWT'yi canlı tutabilir.

Ayrıca bazı Sistemlerde, Uygulamanın fiilen sonlandırılmasının birkaç saniye sürdüğünü fark ettim.


0

Sanırım, fikir burada WindowListener - orada kapanmadan önce çalıştırmak istediğiniz herhangi bir kodu ekleyebilirsiniz.


0

Diğer yorumlara yanıt olarak, DISPOSE_ON_CLOSE uygulamadan düzgün şekilde çıkmıyor gibi görünüyor - yalnızca pencereyi yok ediyor, ancak uygulama çalışmaya devam edecek. Uygulamayı sonlandırmak istiyorsanız EXIT_ON_CLOSE'u kullanın.


Bu cevap James Schek'in cevabının tam tersini ortaya koyuyor. Hangisi doğru? (basit bir uygulamayla test ettiğimde, ikisi de işe yarıyor gibi görünüyor ...)
VEYA Mapper

Bunu şimdi nasıl test ettiğimi hatırlayamıyorum.
JSideris
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.