JDK 5.0 以前,模態對話框僅支援「應用程式級」阻塞,導致 JavaHelp 視窗、Splash Screen 等輔助視窗被錯誤阻塞。Java 6 (Mustang) 引入分層模態模型,精確控制阻塞範圍。
| 模態類型 | 常數 | 阻塞範圍 | 典型用途 |
|---|---|---|---|
| 無模態 | ModalityType.MODELESS | 不阻塞任何視窗 | 工具列、屬性面板、聊天視窗 |
| 文件模態 | ModalityType.DOCUMENT_MODAL | 同一文件根視窗下的所有視窗 (除子層級) | 單文件編輯器的對話框、另存新檔 |
| 應用程式模態 | ModalityType.APPLICATION_MODAL | 同一應用程式所有視窗 (除子層級) | 登入框、關鍵設定、JDK 6+ 預設 setModal(true) |
| 工具箱模態 | ModalityType.TOOLKIT_MODAL | 同一 Toolkit 所有視窗 (跨 Applet) | 極少用,需 AWTPermission("toolkitModality") |
優先序:MODELESS < DOCUMENT_MODAL < APPLICATION_MODAL < TOOLKIT_MODAL。高優先序可阻塞低優先序視窗。
// 核心新建構子 (JDialog 為例)
public JDialog(Window owner, String title, ModalityType modalityType);
public JDialog(Window owner, String title, ModalityType modalityType, GraphicsConfiguration gc);
// 靜態工廠 (Java 8+ 常用)
JDialog dialog = new JDialog((Window) null, "標題", ModalityType.DOCUMENT_MODAL);
// 模態排除:讓視窗不被特定模態阻塞
frame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
ModalExclusionType 三種:
NO_EXCLUDE (預設)APPLICATION_EXCLUDE:不被 APPLICATION_MODAL 阻塞TOOLKIT_EXCLUDE:不被 TOOLKIT_MODAL 阻塞 (需權限)JDK 6 前傳 null 給 JDialog 會隱式建立共享隱形 Frame。JDK 6 起 new JDialog((Window)null, ...) 真正建立無擁有者視窗,配合 DOCUMENT_MODAL 可實現「僅阻塞同文件群」語意。
setAlwaysOnTop(true) 與模態衝突時,行為為平台相依setAlwaysOnTop(true)
Toolkit tk = Toolkit.getDefaultToolkit();
if (tk.isModalityTypeSupported(ModalityType.DOCUMENT_MODAL)) {
// 安全使用
} else {
// 降級為 MODELESS
}
import java.awt.*;
import java.awt.event.*;
public class ModalityDemo {
public static void main(String[] args) {
// 文件 1:紅色 Frame + 無模態對話框 + 文件模態對話框
Frame doc1 = new Frame("文件 1");
doc1.setBackground(Color.RED);
doc1.setBounds(50, 50, 300, 200);
doc1.setVisible(true);
Dialog d11 = new Dialog(doc1, "無模態", ModalityType.MODELESS);
d11.setBounds(100, 100, 200, 100);
d11.setVisible(true);
Dialog d12 = new Dialog(doc1, "文件模態", ModalityType.DOCUMENT_MODAL);
d12.setBounds(350, 100, 200, 100);
d12.setVisible(true); // 僅阻塞 doc1 及其子視窗
// 文件 2:藍色 Frame
Frame doc2 = new Frame("文件 2");
doc2.setBackground(Color.BLUE);
doc2.setBounds(50, 300, 300, 200);
doc2.setVisible(true); // 不被 d12 阻塞
// 排除框架:綠色,不被應用程式模態阻塞
Frame excluded = new Frame("排除框架");
excluded.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
excluded.setBounds(400, 300, 200, 150);
excluded.setVisible(true);
// 應用程式模態檔案對話框 (預設 APPLICATION_MODAL)
FileDialog fd = new FileDialog(doc1, "開啟檔案", FileDialog.LOAD);
fd.setVisible(true); // 阻塞 doc1、doc2,但不阻塞 excluded
}
}
Dialog.setModal(true) 現在對應 APPLICATION_MODAL (舊版為 TOOLKIT_MODAL),行為差異僅在多 Applet/ JWS 場景。new JDialog(frame, true) 保持相容。使用 TOOLKIT_MODAL 或 TOOLKIT_EXCLUDE 需 AWTPermission("toolkitModality"),防止不受信 Applet 阻塞瀏覽器/JWS 視窗。
Java 6 模態 API 以「文件/應用程式/工具箱」三層語意取代單一布林旗標,配合 ModalExclusionType 精準控制視窗互動。現代 Swing/JavaFX 專案應善用此機制,提升多視窗應用的使用者體驗。