2010-09-23 52 views
8

我有一個框架,並希望在用戶關閉它以保存文檔時提示。但是,如果他們取消,框架不應該關閉。Swing WindowListener如何否決JFrame關閉

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會檢查文檔是否髒。如果不是,它什麼也不做,並返回true。如果髒了,它會詢問用戶是否要保存(YES/NO/CANCEL)。如果用戶在這一點取消,它應該中止windowClosing。

我在網上看到的所有建議都涉及到顯式退出windowClosing方法,因此覆蓋JFrame.setDefaultCloseOperation()的使用,並複製JFrame.processWindowEvent()中的代碼。

我其實有一個骯髒的解決方案,但想看看是否有更清潔的。

乾杯

+0

可能重複[如何停止關閉Java應用程序](http://stackoverflow.com/questions/8469097/how-can-i-stop-the-closing-of-a- java-application) – 2013-03-17 00:16:44

回答

15

正確的方法是設置JFrame.setDefaultCloseOperationDO_NOTHING_ON_CLOSE創建窗口時。然後在用戶接受關閉時撥打setVisible(false)dispose(),或者在關閉不被接受時不做任何事情。

JFrame.setDefaultCloseOperation的整個目的只是爲了防止需要實施最簡單的操作WindowListeners。這些默認關閉操作所執行的操作非常簡單。

編輯:

我已經添加了我描述的解決方案。這假定你希望幀被完全刪除。

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

但是,我的聽衆需要知道所需的操作是什麼。我想我可以通過默認關閉操作並在processWindowEvent中複製代碼,但這似乎是一種恥辱。 – 2010-09-23 11:46:42

+0

如果您的意思是用戶所需的操作,那麼是的。在聽衆中,你將不得不彈出對話框。所以如果我明白你想要的東西是正確的:你不應該問問用戶想要什麼,直到你接近結束事件。 – Thirler 2010-09-23 11:51:49

+0

事實上 - 我已經編輯了這個問題,希望能讓這個更清楚。 – 2010-09-23 12:06:29

0

我認爲這是Thirler答案的邏輯表達式,以及我試圖避免的那種。

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

我不喜歡這個的原因是因爲它重複了JFrame中的代碼,並要求框架子類知道所需的操作是什麼當它創建窗口監聽器時。我想我可以重寫setDefaultCloseOperation以將操作傳遞給偵聽器... – 2010-09-23 12:34:40

+0

我將用我的意思編輯我的答案。一般來說,您是製作JFrame的人,因此您知道您想要執行哪種關閉操作,實質上是禁用關閉操作。 – Thirler 2010-09-23 12:35:35

+0

我認爲這是我們不同的地方。我想要一個能夠否決的JFrame關閉,如果用戶說他們不想關閉它,但默認的關閉操作是應用程序的策略而不是框架。 – 2010-09-24 16:28:09

1

Closing an Application可能會使您的過程更容易一些。

+0

謝謝,但我理解這些東西的工作原理(自從導入com.sun.java.swing。*以來,我一直在Swing中進行編程)。我試圖找到一個解決問題的優雅方式。 – 2010-09-24 16:20:38

+0

我以爲我給了一個優雅的解決方案。它爲您管理「提示」和「關閉操作」。我想我不明白你關心的是什麼。 – camickr 2010-09-24 16:56:56

+0

我必須承認我沒有點擊進入你的代碼。現在我已經 - ExitAction實際上不會退出,它關閉了活動框架,它可能會或可能不會退出應用程序。 – 2010-09-24 17:04:01

0

感謝來自Thirler和camickr的意見。這是我的解決方案,我確信有些人會討厭,但避免重複JFrame中的邏輯,並允許客戶端代碼像往常一樣setDefaultCloseOperation。

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