2010-09-23 7 views
8

Ich habe einen Rahmen, und möchte eine Eingabeaufforderung, wenn der Benutzer es zum Speichern des Dokuments schließt. Aber wenn sie abbrechen, sollte der Rahmen nicht schließen.Wie kann ein Swing WindowListener Veto JFrame schließen

frame.addWindowListener(new SaveOnCloseWindowListener(fileState)); 
... 
public class SaveOnCloseWindowListener extends WindowAdapter { 
    private final FileState fileState; 

    public SaveOnCloseWindowListener(FileState fileState) { 
     this.fileState = fileState; 
    } 

    public void windowClosing(WindowEvent e) { 
     if (!fileState.onQuit()) 
      cancelClose(); 
    } 
} 

FileState schaut, ob das Dokument verschmutzt ist. Wenn es nicht ist, tut es nichts und kehrt wahr zurück. Wenn es schmutzig ist, fragt es den Benutzer, ob er speichern möchte (JA/NEIN/ABBRECHEN). Wenn der Benutzer zu diesem Zeitpunkt abbricht, sollte windowClosing abgebrochen werden.

Alle Vorschläge, die ich im Netz gesehen habe beinhalten explizit in der Methode window Verlassen, wodurch die Verwendung von JFrame.setDefaultCloseOperation() überschreiben, und den Code in JFrame.processWindowEvent Duplizieren().

Ich habe eigentlich eine schmutzige Lösung, aber würde gerne sehen, ob es irgendwelche saubereren gibt.

Prost

+0

möglich Duplikat [Wie kann ich den Abschluss einer Java-Anwendung beenden] (http://stackoverflow.com/questions/8469097/how-can-i-stop-the-closing-of-a- Java-Anwendung) –

Antwort

15

Der richtige Weg JFrame.setDefaultCloseOperation-DO_NOTHING_ON_CLOSE gesetzt, wenn das Fenster erstellt wird. Und dann rufen Sie einfach setVisible(false) oder dispose() an, wenn Ihr Benutzer das Schließen annimmt, oder nichts tut, wenn das Schließen nicht akzeptiert wird.

Der ganze Zweck von JFrame.setDefaultCloseOperation ist nur zu verhindern, dass WindowListeners für die einfachsten Aktionen zu implementieren. Die von diesen standardmäßigen Schließvorgängen ausgeführten Aktionen sind sehr einfach.

EDIT:

ich die Lösung hinzugefügt habe ich beschreibe. Dies setzt voraus, dass der Frame vollständig gelöscht werden soll.

frame.setDefaultCloseOperation(setDefaultCloseOperation); 
frame.addWindowListener(new SaveOnCloseWindowListener(fileState)); 
... 

public class SaveOnCloseWindowListener extends WindowAdapter { 
    private final FileState fileState; 

    public SaveOnCloseWindowListener(FileState fileState) { 
     this.fileState = fileState; 
    } 

    public void windowClosing(WindowEvent e) { 
     if (fileState.onQuit()) 
      frame.dispose(); 
    } 
} 
+0

Aber dann müsste mein Zuhörer wissen, was die gewünschte Operation war. Ich nehme an, ich könnte es die Standard-Close-Operation übergeben und den Code in ProcessWindowEvent duplizieren, aber es scheint eine Schande. –

+0

Wenn Sie die gewünschte Operation durch den Benutzer bedeuten, dann ja. Im Listener müssten Sie den Dialog öffnen. Wenn ich also verstehe, was Sie wollen, sollten Sie nicht fragen, was der Benutzer will, bis Sie das Close-Event erhalten. – Thirler

+0

In der Tat - ich habe die Frage bearbeitet, um dies klarer zu machen, hoffe ich. –

0

Ich denke, dass dies der logische Ausdruck von Thirlers Antwort ist, und etwas, was ich vermeiden wollte.

frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); 
frame.addWindowListener(new SaveOnCloseWindowListener(fileState, JFrame.EXIT_ON_CLOSE)); 

public class SaveOnCloseWindowListener extends WindowAdapter { 

    private final int closeOperation; 
    private final Document document; 

    public SaveOnCloseWindowListener(int closeOperation, Document document) { 
     this.closeOperation = closeOperation; 
     this.document = document; 
    } 

    public void windowClosing(WindowEvent e) { 
     if (!document.onClose()) 
      doClose((Window) e.getSource()); 
    } 

    private void doClose(Window w) { 
     switch (closeOperation) { 
     case JFrame.HIDE_ON_CLOSE: 
      w.setVisible(false); 
      break; 
     case JFrame.DISPOSE_ON_CLOSE: 
      w.dispose(); 
      break; 
     case JFrame.DO_NOTHING_ON_CLOSE: 
     default: 
      break; 
     case JFrame.EXIT_ON_CLOSE: 
      System.exit(0); 
      break; 
     } 
    } 
} 
+0

Der Grund, warum ich nicht mag, ist, weil es den Code in JFrame dupliziert, und erfordert die Frame-Unterklasse zu wissen, was die erforderliche Operation ist wenn es den Fenster Listener erstellt. Ich nehme an, ich könnte setDefaultCloseOperation überschreiben, um die Operation an den Listener zu übergeben ... –

+0

Ich werde meine Antwort mit der Lösung, die ich meine, bearbeiten. Im Allgemeinen sind Sie diejenige, die den JFrame erstellt, damit Sie wissen, welche Close-Operation Sie ausführen möchten, im Wesentlichen deaktivieren Sie die Close-Operation. – Thirler

+0

Ich denke, da unterscheiden wir uns. Ich möchte, dass ein JFrame, der in der Lage ist, Veto einzulegen, geschlossen wird, wenn der Benutzer sagt, dass er ihn nicht schließen möchte, die standardmäßige Schließoperation jedoch eine Richtlinie der Anwendung ist, nicht der Rahmen. –

1

Closing an Application könnte Ihnen den Prozess ein wenig erleichtern.

+0

Danke, aber ich verstehe, wie das Zeug funktioniert (ich habe in Swing seit dem Import com.sun.java.swing programmiert. *). Ich versuche eine elegante Lösung für das Problem zu finden. –

+0

Ich dachte, ich gab eine elegante Lösung. Es verwaltet "Aufforderungen" und die "Operation schließen" für Sie. Ich glaube, ich verstehe nicht, worum es geht. – camickr

+0

Ich muss gestehen, dass ich nicht auf Ihren Code geklickt habe. Nun, da ich - ExitAction nicht wirklich beendet habe, schließt es den aktiven Frame, der die App möglicherweise verlassen wird oder nicht. –

0

Dank der Eingabe von Thirler und Camickr. Dies ist meine Lösung, von der ich sicher bin, dass sie einige hassen wird. Sie vermeidet jedoch das Duplizieren von Logik in JFrame und ermöglicht dem Client-Code, wie üblich auf defaultCloseOperation zu setzen.

class MyFrame {   
    @Override protected void processWindowEvent(WindowEvent e) { 
     try { 
      super.processWindowEvent(e); 
     } catch (SaveOnCloseWindowListener.VetoException x) {} 
    } 
} 

public class SaveOnCloseWindowListener extends WindowAdapter { 

    public static class VetoException extends RuntimeException { 
    } 

    private final DocumentController documentController; 

    public SaveOnCloseWindowListener(DocumentController documentController) { 
     this.documentController = documentController; 
    } 

    public void windowClosing(WindowEvent e) { 
     if (!documentController.onClose()) 
      throw new VetoException(); 
    } 
} 
Verwandte Themen