JOptionPane 是 Swing 提供的模態對話框工廠,封裝了常見的用戶交互模式:消息提示、確認選擇、輸入獲取、選項選擇。本文將系統講解其七大靜態方法、參數含義、返回值處理、自定義圖標/按鈕、模態阻塞特性、國際化與無障礙支持,並提供生產級封裝工具類。
| 方法 | 用途 | 返回值類型 | 典型場景 |
|---|---|---|---|
showMessageDialog | 信息/警告/錯誤提示 | void | 操作結果反饋、異常捕獲展示 |
showConfirmDialog | 是/否/取消確認 | int (YES/NO/CANCEL/OK/CLOSED_OPTION) | 刪除確認、保存提示、退出確認 |
showOptionDialog | 完全自定義按鈕 | int (按鈕索引),-1 關閉 | 多選項決策、向導步驟、自定義操作 |
showInputDialog (簡單) | 單行文本輸入 | String (用戶輸入),null 取消 | 重命名、輸入數量、簡單查詢 |
showInputDialog (複雜) | 下拉選擇/組合輸入 | Object (選中值),null 取消 | 枚舉選擇、模板選擇、配置項選擇 |
showInternalMessageDialog 等 | 內部框對話框 | 同上 | JDesktopPane 多文檔界面 (MDI) |
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class JOptionPaneDemo implements ActionListener {
private final JFrame frame = new JFrame("JOptionPane 綜合演示");
private final JToolBar toolBar = new JToolBar("對話框類型");
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new JOptionPaneDemo().createUI());
}
private void createUI() {
// 設置系統觀感
try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }
catch (Exception ignored) {}
String[] types = {"信息提示", "錯誤提示", "警告提示", "確認對話框(是/否)",
"確認對話框(是/否/取消)", "選項對話框", "輸入對話框(文本)",
"輸入對話框(下拉選擇)", "自定義圖標"};
for (String type : types) {
JButton btn = new JButton(type);
btn.setActionCommand(type);
btn.addActionListener(this);
toolBar.add(btn);
}
toolBar.setFloatable(false);
frame.add(toolBar, BorderLayout.NORTH);
frame.add(new JLabel("點擊上方工具欄按鈕測試各類對話框", SwingConstants.CENTER), BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
Component parent = frame; // 父組件,決定對話框位置
switch (cmd) {
case "信息提示" -> JOptionPane.showMessageDialog(parent,
"操作成功完成!", "成功", JOptionPane.INFORMATION_MESSAGE);
case "錯誤提示" -> JOptionPane.showMessageDialog(parent,
"數據庫連接失敗:\n" + "Connection refused: connect",
"錯誤", JOptionPane.ERROR_MESSAGE);
case "警告提示" -> {
Object[] options = {"繼續操作", "取消並回滾"};
int result = JOptionPane.showOptionDialog(parent,
"該操作不可逆,可能導致數據丟失!", "⚠ 危險操作警告",
JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
null, options, options[1]); // 默認聚焦「取消」
handleWarningResult(result);
}
case "確認對話框(是/否)" -> {
int result = JOptionPane.showConfirmDialog(parent,
"確定要刪除選中的 3 條記錄嗎?", "刪除確認",
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (result == JOptionPane.YES_OPTION) {
System.out.println("用戶確認刪除");
}
}
case "確認對話框(是/否/取消)" -> {
int result = JOptionPane.showConfirmDialog(parent,
"文件已修改,退出前是否保存?", "保存確認",
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
handleSaveConfirm(result);
}
case "選項對話框" -> {
Object[] options = {"立即更新", "稍後提醒", "跳過此版本", "查看詳情"};
int result = JOptionPane.showOptionDialog(parent,
"發現新版本 v2.3.1,是否立即更新?", "軟件更新",
JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
null, options, options[0]);
System.out.println("用戶選擇: " + options[result]);
}
case "輸入對話框(文本)" -> {
String name = JOptionPane.showInputDialog(parent,
"請輸入您的姓名:", "用戶信息錄入", JOptionPane.PLAIN_MESSAGE);
if (name != null && !name.isBlank()) {
System.out.println("姓名: " + name.trim());
}
}
case "輸入對話框(下拉選擇)" -> {
Object[] roles = {"管理員", "開發人員", "測試人員", "產品經理", "運營專員"};
Object selected = JOptionPane.showInputDialog(parent,
"請選擇您的角色:", "角色選擇",
JOptionPane.QUESTION_MESSAGE, null, roles, roles[0]);
if (selected != null) {
System.out.println("角色: " + selected);
}
}
case "自定義圖標" -> {
ImageIcon icon = new ImageIcon(getClass().getResource("/icons/app-icon.png"));
JOptionPane.showMessageDialog(parent,
"這是一個帶有自定義圖標的對話框", "品牌化提示",
JOptionPane.PLAIN_MESSAGE, icon);
}
}
}
private void handleWarningResult(int result) {
if (result == 0) System.out.println("用戶選擇繼續操作");
else if (result == 1) System.out.println("用戶取消操作");
else System.out.println("用戶關閉對話框");
}
private void handleSaveConfirm(int result) {
switch (result) {
case JOptionPane.YES_OPTION -> System.out.println("保存並退出");
case JOptionPane.NO_OPTION -> System.out.println("不保存直接退出");
case JOptionPane.CANCEL_OPTION -> System.out.println("取消退出,繼續編輯");
case JOptionPane.CLOSED_OPTION -> System.out.println("關閉對話框,取消退出");
}
}
}
// 定義在 JOptionPane 中
public static final int ERROR_MESSAGE = 0; // 紅色叉號
public static final int INFORMATION_MESSAGE = 1; // 藍色 i
public static final int WARNING_MESSAGE = 2; // 黃色三角形
public static final int QUESTION_MESSAGE = 3; // 藍色問號
public static final int PLAIN_MESSAGE = -1; // 無圖標
public static final int DEFAULT_OPTION = -1; // 由 L&F 決定(通常 OK)
public static final int YES_NO_OPTION = 0; // 是 / 否
public static final int YES_NO_CANCEL_OPTION = 1; // 是 / 否 / 取消
public static final int OK_CANCEL_OPTION = 2; // 確定 / 取消
int showOptionDialog(Component parent, Object message, String title,
int optionType, int messageType,
Icon icon, Object[] options, Object initialValue)
options:按鈕文本陣列(String)或組件陣列(JButton 等),長度決定按鈕數initialValue:默認聚焦按鈕(通常指定「安全」選項)showXxxDialog 默認應用程序級模態:阻塞父窗口及同屬一個 Window 的所有組件JDialog 並設置 setModal(false)null:對話框居中於屏幕Frame/Dialog:對話框居中於該窗口,並共享模態範圍Component:對話框居中於該組件所在窗口this 或 parentFrame)
// 1. 設置默認按鈕文本(全局生效)
UIManager.put("OptionPane.yesButtonText", "確定");
UIManager.put("OptionPane.noButtonText", "取消");
UIManager.put("OptionPane.cancelButtonText", "關閉");
UIManager.put("OptionPane.okButtonText", "確認");
// 2. 或使用 ResourceBundle 動態加載
ResourceBundle bundle = ResourceBundle.getBundle("messages", Locale.getDefault());
UIManager.put("OptionPane.yesButtonText", bundle.getString("yes"));
// 圖標
Icon customIcon = new ImageIcon(getClass().getResource("/icons/warning.png"));
JOptionPane.showMessageDialog(parent, "內容", "標題", JOptionPane.PLAIN_MESSAGE, customIcon);
// 複雜消息組件(多行、表格、進度條)
JPanel panel = new JPanel(new BorderLayout());
panel.add(new JLabel("詳細信息:"), BorderLayout.NORTH);
panel.add(new JScrollPane(new JTextArea(logText)), BorderLayout.CENTER);
JOptionPane.showMessageDialog(parent, panel, "日誌詳情", JOptionPane.INFORMATION_MESSAGE);
String input;
do {
input = JOptionPane.showInputDialog(parent,
"請輸入郵箱:", "郵箱驗證", JOptionPane.QUESTION_MESSAGE);
if (input == null) return; // 用戶取消
if (!input.matches("^[\\w.]+@[\\w.]+\\.\\w+$")) {
JOptionPane.showMessageDialog(parent, "郵箱格式不正確", "錯誤", JOptionPane.ERROR_MESSAGE);
}
} while (!input.matches("^[\\w.]+@[\\w.]+\\.\\w+$"));
import javax.swing.*;
import java.awt.*;
import java.util.ResourceBundle;
public final class DialogUtils {
private DialogUtils() {}
/** 信息提示 */
public static void info(Component parent, String message) {
show(parent, message, "提示", JOptionPane.INFORMATION_MESSAGE);
}
/** 成功提示(綠色風格,需自定義圖標) */
public static void success(Component parent, String message) {
show(parent, message, "成功", JOptionPane.INFORMATION_MESSAGE); // 可換自定義綠色圖標
}
/** 警告提示 */
public static void warn(Component parent, String message) {
show(parent, message, "警告", JOptionPane.WARNING_MESSAGE);
}
/** 錯誤提示(支援異常自動提取堆疊) */
public static void error(Component parent, String message) {
error(parent, message, null);
}
public static void error(Component parent, String message, Throwable t) {
String fullMsg = t != null ? message + "\n\n詳細: " + t.getMessage() : message;
show(parent, fullMsg, "錯誤", JOptionPane.ERROR_MESSAGE);
if (t != null) t.printStackTrace(); // 記錄日誌
}
/** 是/否確認 */
public static boolean confirm(Component parent, String message) {
return confirm(parent, message, "確認", JOptionPane.YES_NO_OPTION);
}
public static boolean confirm(Component parent, String message, String title) {
return confirm(parent, message, title, JOptionPane.YES_NO_OPTION);
}
public static boolean confirm(Component parent, String message, String title, int optionType) {
int result = JOptionPane.showConfirmDialog(parent, message, title, optionType, JOptionPane.QUESTION_MESSAGE);
return result == JOptionPane.YES_OPTION;
}
/** 是/否/取消確認 → 返回三態枚舉 */
public enum ConfirmResult { YES, NO, CANCEL }
public static ConfirmResult confirmYesNoCancel(Component parent, String message) {
int result = JOptionPane.showConfirmDialog(parent, message, "確認", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
return switch (result) {
case JOptionPane.YES_OPTION -> ConfirmResult.YES;
case JOptionPane.NO_OPTION -> ConfirmResult.NO;
default -> ConfirmResult.CANCEL;
};
}
/** 文本輸入 */
public static String input(Component parent, String message) {
return (String) JOptionPane.showInputDialog(parent, message, "輸入", JOptionPane.PLAIN_MESSAGE);
}
/** 下拉選擇 */
public static T select(Component parent, String message, String title, T[] options, T defaultOption) {
Object selected = JOptionPane.showInputDialog(parent, message, title, JOptionPane.QUESTION_MESSAGE, null, options, defaultOption);
return (T) selected;
}
/** 完全自定義選項 */
public static int showOptions(Component parent, String message, String title, Object[] options, int defaultIndex) {
return JOptionPane.showOptionDialog(parent, message, title, JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[defaultIndex]);
}
private static void show(Component parent, String message, String title, int messageType) {
JOptionPane.showMessageDialog(parent, message, title, messageType);
}
}
JOptionPane 以靜態工廠方法、模態阻塞、豐富預設類型、可擴展參數成為 Swing 交互的首選。掌握以下要點即可應對 95% 場景:
messageType 控制圖標,optionType 控制按鈕組合showOptionDialog 實現完全自定義(按鈕文本、圖標、默認聚焦)parent 確保定位正確int 索引、String 文本、Object 選中值、null 取消UIManager.put 覆蓋默認按鈕文本DialogUtils 統一項目風格、簡化業務調用本文代碼可直接運行體驗所有對話框類型,工具類可直接納入項目公共庫。