2010-09-23 7 views
8

Ho un frame e voglio chiedere quando l'utente lo chiude per salvare il documento. Ma se annullano, la cornice non dovrebbe chiudersi.Come può un utente Swing WindowListener JFrame di chiusura

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 controlla se il documento è sporco. Se non lo è, non fa nulla e restituisce il vero. Se è sporco, chiede all'utente se vuole salvare (SÌ/NO/ANNULLA). Se l'utente annulla a questo punto, dovrebbe interrompere la finestra Chiusura.

Tutti i suggerimenti che ho visto in rete implicano esplicitamente l'uscita dal metodo windowClosing, annullando quindi l'uso di JFrame.setDefaultCloseOperation() e la duplicazione del codice in JFrame.processWindowEvent().

In realtà ho una soluzione sporca, ma vorrei vedere se ci sono quelli più puliti.

Acclamazioni

+0

possibile duplicato di [Come posso fermare la chiusura di un'applicazione Java] (http://stackoverflow.com/questions/8469097/how-can-i-stop-the-closing-of-a- java-application) –

risposta

15

Il modo giusto è impostato JFrame.setDefaultCloseOperation-DO_NOTHING_ON_CLOSE quando viene creata la finestra. E poi chiama semplicemente setVisible(false) o dispose() quando l'utente accetta la chiusura o non fa nulla quando la chiusura non viene accettata.

L'intero scopo di JFrame.setDefaultCloseOperation è solo per evitare la necessità di implementare WindowListeners per le azioni più semplici. Le azioni eseguite da queste operazioni di chiusura predefinite sono molto semplici.

EDIT:

Ho aggiunto la soluzione che sto descrivendo. Questo presuppone che tu voglia che il frame sia completamente cancellato.

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

Ma poi il mio ascoltatore avrebbe bisogno di sapere qual era l'operazione desiderata. Suppongo che potrei passarlo l'operazione di chiusura di default e duplicare il codice in processWindowEvent, ma sembra un peccato. –

+0

Se si intende l'operazione desiderata dall'utente, allora sì. Nell'ascoltatore dovresti far apparire la finestra di dialogo. Quindi, se capisco cosa vuoi che tu abbia correttamente: non dovresti chiedere cosa vuole l'utente fino a quando non ottieni l'evento vicino. – Thirler

+0

Infatti, ho modificato la domanda per far sì che questo sia più chiaro. –

0

Penso che questo sia l'espressione logica di risposta di Thirler, e il tipo di quello che stavo cercando di evitare.

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

Il motivo per cui non mi piace è perché duplica il codice in JFrame e richiede la sottoclasse del frame per sapere quale sia l'operazione richiesta quando crea il listener di finestre. Suppongo di poter sovrascrivere setDefaultCloseOperation per passare l'operazione all'ascoltatore ... –

+0

Modificherò la mia risposta con la soluzione intendo. In generale sei tu quello che crea JFrame, quindi sai quale operazione di chiusura vuoi, in pratica disabiliti l'operazione di chiusura. – Thirler

+0

Penso che sia dove ci differenziamo. Voglio un JFrame che è in grado di chiudere il veto se l'utente dice che non vogliono chiuderlo, ma dove l'operazione di chiusura predefinita è una politica dell'applicazione, non il frame. –

1

Closing an Application potrebbe rendere il processo un po 'più facile per voi.

+0

Grazie, ma capisco come funziona la roba (ho programmato in Swing dall'importazione di com.sun.java.swing. *). Sto cercando di trovare un modo elegante per risolvere il problema. –

+0

Pensavo di aver dato una soluzione elegante. Gestisce "prompt" e "operazione di chiusura" per te. Immagino di non capire quale sia la tua preoccupazione. – camickr

+0

Devo confessare che non ho fatto clic sul tuo codice. Ora che ho - ExitAction in realtà non esce, chiude il frame attivo, che può o meno uscire dall'app. –

0

Grazie all'input di Thirler e camickr. Questa è la mia soluzione, che sono sicuro che alcuni odieranno, ma eviterà la duplicazione della logica in JFrame e consente al codice client di impostareDefaultCloseOperation come al solito.

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