Java Swing 的對話框類別有兩個, 一是重量級 (heavy-weight) 的 JDialog, 可製作出所希望的對話版面, 運用彈性最大, 當然設定方式也就比較複雜, 例如可設定為強制模式 (modal) 或非強制模式 (non-modal) 等等. 二是 JOptionPane 這個設定超簡單的類別, 也是 Swing 程式設計中最常用的. 要注意的是, JOptionPane 乃強制對話框, 必須按下選項按鈕關閉對話框後, 才能繼續處理其他視窗工作.
其次, JOptionPane 並非 JDialog 的子類別, 而是純 Java 設計的輕量級元件, 直接繼承自 JComponent. 但是實際上 JOptionPane 背後是使用 JDialog 來產生視窗, 因此如果要完全套用 Swing 主題風格, 仍必須用 JDialog.setDefaultLookAndFeel() 這個靜態方法設定為預設的 Metal 介面才行, 否則對話框會套用作業系統外框.
JDialog.setDefaultLookAndFeelDecorated(true);
其 API 參考 :
# http://docs.oracle.com/javase/7/docs/api/
# http://docs.oracle.com/javase/7/docs/api/javax/swing/JOptionPane.html
# Manning : Swing second edition 目錄 (CH14, P439)
JOptionPane 類別雖然有建構子, 但我們在使用 JOptionPane 類別時, 通常不必利用建構子產生物件實體, 而是直接使用 showMessageDialog(), showConfirmDialog(), showInputDialog(), 以及 showOptionDialog() 這三個靜態方法, 並利用此類別定義的屬性整數常數來進行設定, 包括五個訊息類型 (message type), 以及四個選項按鈕類型 (option type) :
訊息類型 (message type) :
- JOptionPane.ERROR_MESSAGE (=0)
- JOptionPane.INFORMATION_MESSAGE (=1)
- JOptionPane.WARNING_MESSAGE (=2)
- JOptionPane.QUESTION_MESSAGE (=3)
- JOptionPane.PLAIN_MESSAGE (= -1)
- JOptionPane.DEFAULT_OPTION (= -1)
- JOptionPane.YES_NO_OPTION (=0)
- JOptionPane.YES_NO_CANCEL_OPTION (=1)
- JOptionPane.OK_CANCEL_OPTION (=2)
- 訊息框 (Message Dialog) :
只是告知使用者某項訊息而已, 例如檔案不存在, 帳號密碼錯誤等等. 其按鈕選項只有一個 OK 或確定鈕, 只能按此關閉訊息框. - 確認框 (Confirm Dialog) :
用來要求使用者確認某個決定, 例如刪除檔案, 關閉視窗等等, 因此至少有 YES/NO 兩個選項按鈕, 一般是 YES/NO/CANCEL 三個按鈕. - 輸入框 (Input Dialog) :
用來要求使用者輸入資訊, 例如帳號密碼, 搜尋關鍵字等等, 因此必須要有一個 TextField 欄位以及一個 OK 按鈕. - 選項框 (Option Dialog) :
這是確認框的變形, 可自訂選項按鈕上的文字, 而非只有 YES_NO_CANCEL_OK.
JOptionPane.showMessageDialog(Component parent, Object message [,
String title, int messageType [, Icon icon]]])
亦即最少需要兩個參數, 第一個是父容器元件, 例如 JFrame, JApplet, JDialog 等. 第二個是要顯示的訊息. 這時預設的標題為 "資訊", 訊息類型為 1 (即圖示為 i). 也可以傳入第三與第四參數, 指定所要的標題與圖示. 如果不要圖示, 只顯示訊息, 則訊息類型可以傳入 PLAIN_MESSAGE. 若傳入一個 Icon 或 ImageIcon 物件, 則可以自訂圖示, 如下列範例所示 :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JOptionPane1 implements ActionListener {
JFrame f;
public static void main(String argv[]) {
new JOptionPane1();
}
public JOptionPane1() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JOptionPane Test");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
cp.setLayout(null);
f.setVisible(true);
//Build Elements
JOptionPane.showMessageDialog(f,"Hello World! 您好");
JOptionPane.showMessageDialog(f,"Hello World! 您好",
"問候", JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(f,"Hello World! 您好",
"問候", JOptionPane.INFORMATION_MESSAGE);
JOptionPane.showMessageDialog(f,"Hello World! 您好",
"問候", JOptionPane.WARNING_MESSAGE);
JOptionPane.showMessageDialog(f,"Hello World! 您好",
"問候", JOptionPane.QUESTION_MESSAGE);
JOptionPane.showMessageDialog(f,"Hello World! 您好",
"問候", JOptionPane.PLAIN_MESSAGE);
JOptionPane.showMessageDialog(f,"Hello World! 您好",
"問候", JOptionPane.PLAIN_MESSAGE,
new ImageIcon("icon.jpg"));
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
public void actionPerformed(ActionEvent e) {
//if (e.getSource()==id) {}
}
}
class WindowHandler extends WindowAdapter {
JFrame f;
public WindowHandler(JFrame f) {this.f=f;}
public void windowClosing(WindowEvent e) {
int result=JOptionPane.showConfirmDialog(f,
"確定要結束程式嗎?",
"確認訊息",
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
if (result==JOptionPane.YES_OPTION) {System.exit(0);}
}
}
預設 (INFORMATION)
ERROR
INFORMATION
WARNING
QUESTION
自訂圖示
JOptionPane.showConfirmDialog(Component parent, Object message [,
String title [, int optionType [,
messageType [, Icon icon]]]])
同樣可以用 messageType 設定適當的圖示, 但下列範例主要是展示 optionType 選項按鈕的差異, 故下列範例中一律用 information 圖示 :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JOptionPane2 implements ActionListener {
JFrame f;
public static void main(String argv[]) {
new JOptionPane2();
}
public JOptionPane2() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JOptionPane Test");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
cp.setLayout(null);
f.setVisible(true);
//Build Elements
int mType=JOptionPane.INFORMATION_MESSAGE;
JOptionPane.showConfirmDialog(f,"DEFAULT_OPTION","確認",
JOptionPane.DEFAULT_OPTION,mType);
JOptionPane.showConfirmDialog(f,"YES_NO_OPTION","確認",
JOptionPane.YES_NO_OPTION,mType);
JOptionPane.showConfirmDialog(f,"YES_NO_CANCEL_OPTION","確認",
JOptionPane.YES_NO_CANCEL_OPTION,mType);
JOptionPane.showConfirmDialog(f,"OK_CANCEL_OPTION","確認",
JOptionPane.OK_CANCEL_OPTION,mType);
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
public void actionPerformed(ActionEvent e) {
//if (e.getSource()==id) {}
}
}
class WindowHandler extends WindowAdapter {
JFrame f;
public WindowHandler(JFrame f) {this.f=f;}
public void windowClosing(WindowEvent e) {
int result=JOptionPane.showConfirmDialog(f,
"確定要結束程式嗎?",
"確認訊息",
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
if (result==JOptionPane.YES_OPTION) {System.exit(0);}
}
}
- JOptionPane.YES_OPTION=0
- JOptionPane.NO_OPTION=1
- JOptionPane.CANCEL_OPTION=2
- JOptionPane.OK_OPTION=0
- JOptionPane.CLOSED_OPTION= -1
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JOptionPane3 implements ActionListener {
JFrame f;
public static void main(String argv[]) {
new JOptionPane3();
}
public JOptionPane3() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JOptionPane Test");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
cp.setLayout(null);
f.setVisible(true);
//Build Elements
int opt=JOptionPane.showConfirmDialog(f,"YES_NO_CANCEL_OPTION","確認",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.INFORMATION_MESSAGE);
if (opt==JOptionPane.YES_OPTION) {
JOptionPane.showMessageDialog(f,"您按了 YES (是) " + opt);
}
else if (opt==JOptionPane.NO_OPTION) {
JOptionPane.showMessageDialog(f,"您按了 NO (否) " + opt);
}
else if (opt==JOptionPane.CANCEL_OPTION) {
JOptionPane.showMessageDialog(f,"您按了 CANCEL (取消) " + opt);
}
else if (opt==JOptionPane.CLOSED_OPTION) {
JOptionPane.showMessageDialog(f,"您按了 CLOSE (關閉) " + opt);
}
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
public void actionPerformed(ActionEvent e) {
//if (e.getSource()==id) {}
}
}
class WindowHandler extends WindowAdapter {
JFrame f;
public WindowHandler(JFrame f) {this.f=f;}
public void windowClosing(WindowEvent e) {
int result=JOptionPane.showConfirmDialog(f,
"確定要結束程式嗎?",
"確認訊息",
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
if (result==JOptionPane.YES_OPTION) {System.exit(0);}
}
}
接下來測試輸入盒, 用在程式執行途中需要使用者輸入資料時, 會在對話框中顯示一個文字欄位或者下拉式選單 (ComboBox). 但其建構子有點怪, 跟上面訊息盒與確認盒不同的是, 它最少的參數是一個, 也就是輸入盒的提示字串, 不需要特別指定父容器物件, 預設就是目前的父容器, messageType 預設為 QUESTION, 傳回值為字串, 即輸入之資料, 如下列範例所示 :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JOptionPane4 implements ActionListener {
JFrame f;
public static void main(String argv[]) {
new JOptionPane4();
}
public JOptionPane4() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JOptionPane Test");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
cp.setLayout(null);
f.setVisible(true);
//Build Elements
String input=JOptionPane.showInputDialog("請輸入姓名");
JOptionPane.showMessageDialog(f,"您輸入的是 : " + input);
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
public void actionPerformed(ActionEvent e) {
//if (e.getSource()==id) {}
}
}
class WindowHandler extends WindowAdapter {
JFrame f;
public WindowHandler(JFrame f) {this.f=f;}
public void windowClosing(WindowEvent e) {
int result=JOptionPane.showConfirmDialog(f,
"確定要結束程式嗎?",
"確認訊息",
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
if (result==JOptionPane.YES_OPTION) {System.exit(0);}
}
}
其他的建構子可以寫成一個通式, 比訊息盒與確認盒多了兩個參數, 這是用來製作下拉式選單輸入用的 :
JOptionPane.showInputDialog(Component parent, Object message [,
String title, int messageType [, Icon icon [,
Object[] selection [, Object initialSelection]]]])
如下列範例所示 :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JOptionPane5 implements ActionListener {
JFrame f;
public static void main(String argv[]) {
new JOptionPane5();
}
public JOptionPane5() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JOptionPane Test");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
cp.setLayout(null);
f.setVisible(true);
//Build Elements
int mType=JOptionPane.INFORMATION_MESSAGE;
String in1=JOptionPane.showInputDialog(f,"請輸入姓名","輸入",mType);
JOptionPane.showMessageDialog(f,"您輸入的是 : " + in1);
String[] gender={"男", "女"};
String in2=(String)JOptionPane.showInputDialog(f,"請輸入性別","輸入",
mType,null,gender,"男");
JOptionPane.showMessageDialog(f,"您輸入的是 : " + in2);
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
public void actionPerformed(ActionEvent e) {
//if (e.getSource()==id) {}
}
}
class WindowHandler extends WindowAdapter {
JFrame f;
public WindowHandler(JFrame f) {this.f=f;}
public void windowClosing(WindowEvent e) {
int result=JOptionPane.showConfirmDialog(f,
"確定要結束程式嗎?",
"確認訊息",
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
if (result==JOptionPane.YES_OPTION) {System.exit(0);}
}
}
這裡要特別注意, 使用 ComboBox 當輸入時, 輸入盒的傳回值是 Object 物件, 不是 String, 因此必須強制轉型. 其次, 圖示若不加以設定, 傳入 null 即可.
輸入盒一次只能輸入一個資料, 適合簡單的應用, 如果要一次可輸入多項資料, 就要用 JDialog 來設計.
最後來測試選項對話框. 這其實是確認框的變形, 可傳入陣列修改選項按鈕上的文字, 但傳回值不變. 其靜態方法只有一個, 並無多載, 格式與確認盒相仿, 只是多了兩個參數 :
JOptionPane.showOptionDialog(Component parent, Object message, String title,
int optionType, int messageType, Icon icon,
Object[] options, Object initialValue)
其中, 最後兩個參數就是用來設定選項按鈕的, options 為一字串陣列, 其排列順序與第三個參數 optionType 相對應, 例如 optionType 為 JOptionPane.YES_NO_CANCEL_OPTION, 而 options 字串陣列為 {"接受","不接受","取消"}, 則 "YES" 按鈕就被 "接受" 取代, "NO" 按鈕被 "不接受" 取代, "CANCEL" 鈕則被 "取消" 取代, 其傳回值當然也要相互對應, 如下列範例所示 :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JOptionPane6 implements ActionListener {
JFrame f;
public static void main(String argv[]) {
new JOptionPane6();
}
public JOptionPane6() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JOptionPane Test");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
cp.setLayout(null);
f.setVisible(true);
//Build Elements
int mType=JOptionPane.QUESTION_MESSAGE;
int oType=JOptionPane.YES_NO_CANCEL_OPTION;
String[] options={"接受","不接受","取消"};
int opt=JOptionPane.showOptionDialog(f,"您接受保密條款嗎?",
"請選擇",oType,mType,null,options,"接受");
if (opt==JOptionPane.YES_OPTION){
JOptionPane.showMessageDialog(f,"您選擇的是 : 接受 " + opt);
}
if (opt==JOptionPane.NO_OPTION){
JOptionPane.showMessageDialog(f,"您選擇的是 : 不接受 " + opt);
}
if (opt==JOptionPane.CANCEL_OPTION){
JOptionPane.showMessageDialog(f,"您選擇的是 : 取消 " + opt);
}
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
public void actionPerformed(ActionEvent e) {
//if (e.getSource()==id) {}
}
}
class WindowHandler extends WindowAdapter {
JFrame f;
public WindowHandler(JFrame f) {this.f=f;}
public void windowClosing(WindowEvent e) {
int result=JOptionPane.showConfirmDialog(f,
"確定要結束程式嗎?",
"確認訊息",
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
if (result==JOptionPane.YES_OPTION) {System.exit(0);}
}
}
可見 YES_NO_CANCEL 按鈕已經被替換成指定的字串了. 最後我把上述測試整合寫到選項功能表 JMenuBar 裡面, 如下列範例所示 :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class JOptionPane7 implements ActionListener {
JFrame f;
JMenuBar mb;
JMenu jop,messages,options;
JMenuItem[] dialog;
JRadioButtonMenuItem[] mType;
JRadioButtonMenuItem[] oType;
public static void main(String argv[]) {
new JOptionPane7();
}
public JOptionPane7() {
//Setup JFrame
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
f=new JFrame("JOptionPane Test");
f.setSize(400,300);
f.setLocationRelativeTo(null);
Container cp=f.getContentPane();
cp.setLayout(null);
f.setVisible(true);
//Build Elements
mb=new JMenuBar();
jop=new JMenu("JOptionPane");
messages=new JMenu("Message Type");
options=new JMenu("Option Type");
dialog=new JMenuItem[4];
dialog[0]=new JMenuItem("setMessageDialog()");
dialog[1]=new JMenuItem("setConfirmDialog()");
dialog[2]=new JMenuItem("setInputDialog()");
dialog[3]=new JMenuItem("setOptionDialog()");
mType=new JRadioButtonMenuItem[5];
mType[0]=new JRadioButtonMenuItem("ERROR_MESSAGE");
mType[1]=new JRadioButtonMenuItem("INFORMATION_MESSAGE");
mType[2]=new JRadioButtonMenuItem("WARNING_MESSAGE");
mType[3]=new JRadioButtonMenuItem("QUESTION_MESSAGE");
mType[4]=new JRadioButtonMenuItem("PLAIN_MESSAGE");
oType=new JRadioButtonMenuItem[4];
oType[0]=new JRadioButtonMenuItem("DEFAULT_OPTION");
oType[1]=new JRadioButtonMenuItem("YES_NO_OPTION");
oType[2]=new JRadioButtonMenuItem("YES_NO_CANCEL_OPTION");
oType[3]=new JRadioButtonMenuItem("OK_CANCEL_OPTION");
for (int i=0; i<dialog.length; i++) {
jop.add(dialog[i]);
dialog[i].addActionListener(this);
}
jop.addSeparator();
ButtonGroup mgroup=new ButtonGroup();
for (int i=0; i<mType.length; i++) {
messages.add(mType[i]);
mgroup.add(mType[i]);
mType[i].addActionListener(this);
if (i==0) {mType[i].setSelected(true);}
}
ButtonGroup ogroup=new ButtonGroup();
for (int i=0; i<oType.length; i++) {
options.add(oType[i]);
ogroup.add(oType[i]);
oType[i].addActionListener(this);
if (i==0) {oType[i].setSelected(true);}
}
jop.add(messages);
jop.add(options);
mb.add(jop);
f.setJMenuBar(mb);
//Close JFrame
f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
f.addWindowListener(new WindowHandler(f));
}
public void actionPerformed(ActionEvent e) {
String cmd=e.getActionCommand();
if (cmd.equals("setMessageDialog()")) {
int mtype=getMessageType();
JOptionPane.showMessageDialog(f,"Hello World! 您好","資訊",mtype);
}
if (cmd.equals("setConfirmDialog()")) {
int mtype=getMessageType();
int otype=getOptionType();
int opt=JOptionPane.showConfirmDialog(f,cmd,"確認",otype,mtype);
showSelectedOption(opt);
}
if (cmd.equals("setInputDialog()")) {
int mtype=getMessageType();
String input=JOptionPane.showInputDialog(f,cmd,"輸入",mtype);
JOptionPane.showMessageDialog(f,"您輸入的是 : " + input);
}
if (cmd.equals("setOptionDialog()")) {
String[] options={"接受","不接受","取消"};
int mtype=getMessageType();
int otype=getOptionType();
int opt=JOptionPane.showOptionDialog(f,cmd,"請選擇",otype,mtype,null,
options,"接受");
showSelectedOption(opt);
}
}
public int getMessageType() {
int type=1;
for (int i=0; i<mType.length; i++) {
if (mType[i].isSelected()) {
switch (mType[i].getText()) {
case "ERROR_MESSAGE" : type=0;break;
case "INFORMATION_MESSAGE" : type=1;break;
case "WARNING_MESSAGE" : type=2;break;
case "QUESTION_MESSAGE" : type=3;break;
case "PLAIN_MESSAGE" : type=-1;break;
}
}
}
return type;
}
public int getOptionType() {
int type=1;
for (int i=0; i<oType.length; i++) {
if (oType[i].isSelected()) {
switch (oType[i].getText()) {
case "DEFAULT_OPTION" : type=-1;break;
case "YES_NO_OPTION" : type=0;break;
case "YES_NO_CANCEL_OPTION" : type=1;break;
case "OK_CANCEL_OPTION" : type=2;break;
}
}
}
return type;
}
public void showSelectedOption(int opt) {
if (opt==JOptionPane.YES_OPTION) {
JOptionPane.showMessageDialog(f,"您按了 YES (是) " + opt);
}
else if (opt==JOptionPane.NO_OPTION) {
JOptionPane.showMessageDialog(f,"您按了 NO (否) " + opt);
}
else if (opt==JOptionPane.CANCEL_OPTION) {
JOptionPane.showMessageDialog(f,"您按了 CANCEL (取消) " + opt);
}
else if (opt==JOptionPane.CLOSED_OPTION) {
JOptionPane.showMessageDialog(f,"您按了 CLOSE (關閉) " + opt);
}
else if (opt==JOptionPane.OK_OPTION) {
JOptionPane.showMessageDialog(f,"您按了 OK (確定) " + opt);
}
}
}
class WindowHandler extends WindowAdapter {
JFrame f;
public WindowHandler(JFrame f) {this.f=f;}
public void windowClosing(WindowEvent e) {
int result=JOptionPane.showConfirmDialog(f,
"確定要結束程式嗎?",
"確認訊息",
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
if (result==JOptionPane.YES_OPTION) {System.exit(0);}
}
}
在這個整合範例中, 我把訊息類型與選項類型分別放在不同的選單中, 利用兩個 ButtonGroup 將兩組選項圓鈕綁起來形成單選功能. 兩個自訂函數 getMessageType() 與 getOptionType() 分別用來獲取兩組選項圓鈕的設定, 這裡以迴圈掃描方式偵測選了哪一個選項. 另外, 確認盒與選項盒有傳回選項值, 所以用 showSelectedOption() 來顯示此值.
沒有留言 :
張貼留言