Jaki jest właściwy sposób usunięcia aplikacji Swing z kodu i jakie są pułapki?
Próbowałem automatycznie zamknąć aplikację po uruchomieniu licznika czasu. Ale po prostu dzwoniąc dispose()
na JFrame
nie załatwi - okno zniknęło ale aplikacja nie zakończy. Jednak zamykanie okna przyciskiem zamykania powoduje zakończenie działania aplikacji. Co powinienem zrobić?
Odpowiedzi:
Domyślną akcję zamykania JFrame można ustawić na „
DISPOSE_ON_CLOSE
” zamiastEXIT_ON_CLOSE
(dlaczego ludzie nadal używają EXIT_ON_CLOSE jest poza mną).Jeśli masz jakieś niewyświetlone okna lub wątki niebędące demonami, Twoja aplikacja nie zostanie zakończona. Należy to uznać za błąd (a rozwiązanie go za pomocą System.exit to bardzo zły pomysł).
Najczęstszymi winowajcami są java.util.Timer i utworzony przez Ciebie niestandardowy wątek. Oba powinny być ustawione na demona lub jawnie zabite.
Jeśli chcesz sprawdzić wszystkie aktywne ramki, możesz użyć
Frame.getFrames()
. Jeśli wszystkie okna / ramki zostaną usunięte, użyj debugera, aby sprawdzić, czy nie działają nadal wątki niebędące demonami.źródło
back
okna? Jeśli drugie okno zostanie następnie zamknięte, aDISPOSE_ON_CLOSE
program nie zostanie zakończony, ponieważ pierwsze okno jest nadal „niewykorzystane” ... czy istnieje sposób na rozwiązanie tego problemu bez użyciaDISPOSE_ON_CLOSE
?Myślę, że EXIT_ON_CLOSE
wcześniej
System.exit(0)
jest lepsze, ponieważ możesz napisać odbiornik okien, aby wykonać pewne operacje czyszczenia przed faktycznym opuszczeniem aplikacji.Ten detektor okien umożliwia zdefiniowanie:
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."); }
źródło
Próbować:
System.exit(0);
Surowy, ale skuteczny.
źródło
Może być bezpiecznym sposobem:
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(); } });
źródło
Frame
wielką literą, dokładnie tak, jak nazwa klasy…Poniższy program zawiera kod, który zakończy działanie programu bez dodatkowych wątków bez jawnego wywołania System.exit (). Aby zastosować ten przykład do aplikacji używających wątków / nasłuchiwaczy / timerów / itp., Wystarczy wstawić kod czyszczenia żądający (i, jeśli ma to zastosowanie, oczekiwanie) na ich zakończenie, zanim WindowEvent zostanie ręcznie zainicjowany w actionPerformed ().
Dla tych, którzy chcą skopiować / wkleić kod działający dokładnie tak, jak pokazano, na końcu dołączona jest nieco brzydka, ale poza tym nieistotna główna metoda.
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); } }); } }
źródło
Jeśli dobrze cię rozumiem, chcesz zamknąć aplikację, nawet jeśli użytkownik nie kliknął przycisku zamykania. Będziesz musiał zarejestrować WindowEvents, być może za pomocą addWindowListener () lub enableEvents (), w zależności od tego, co bardziej odpowiada Twoim potrzebom.
Następnie możesz wywołać zdarzenie za pomocą wywołania processWindowEvent (). Oto przykładowy kod, który utworzy JFrame, odczekaj 5 sekund i zamknie JFrame bez interakcji użytkownika.
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(); } }
Jak widać, metoda processWindowEvent () powoduje wywołanie zdarzenia WindowClosed, w którym istnieje możliwość wyczyszczenia kodu przed zamknięciem aplikacji.
źródło
Zapoznaj się z dokumentacją Oracle .
Począwszy od JDK 1.4, aplikacja kończy działanie, jeśli:
Narożniki:
Dokument stwierdza, że niektóre pakiety tworzą komponenty, które można wyświetlać, bez ich zwalniania. Program, który wywołuje Toolkit.getDefaultToolkit (), nie zakończy działania. jest między innymi podany jako przykład.
Również inne Procesy mogą utrzymywać AWT przy życiu, gdy z jakiegokolwiek powodu wysyłają zdarzenia do natywnej kolejki zdarzeń.
Zauważyłem również, że w niektórych systemach potrzeba kilku sekund, zanim aplikacja faktycznie się zakończy.
źródło
Myślę, że idea jest tutaj WindowListener - możesz dodać tam dowolny kod, który chciałbyś uruchomić, zanim coś się wyłączy
źródło
W odpowiedzi na inne komentarze, DISPOSE_ON_CLOSE nie wydaje się prawidłowo wychodzić z aplikacji - niszczy tylko okno, ale aplikacja będzie nadal działać. Jeśli chcesz zamknąć aplikację, użyj EXIT_ON_CLOSE.
źródło