BorderLayout.NORTH บทท่ี 11: GUI และ Event Handling
BorderLayout.EAST
BorderLayout.CENTER
BorderLayout.WEST BorderLayout.SOUTH intro. to Java (FEU.faa)
JButton JTextField
ภาพท่ี 11.2 การวาง JButton และ JTextField ดว ย BorderLayout
เราสามารถกําหนดตาํ แหนงการวาง object ดว ย border layout ไดหาตําแหนงคอื ดา นบน
(NORTH), ดานลาง (SOUTH), ดานซาย (WEST), ดานขวา (EAST) และตรงกลาง (CENTER)
เทา น้นั โปรแกรมตวั อยา งของเราดัดแปลงมาจากโปรแกรม DateTimeSwingApp.java โดยเรา
ไดเ พม่ิ ปมุ อีกสองปมุ และ text field ที่ใชแสดงขอความอกี สองตัว เราไดกาํ หนดใหป ุมดา นซา ย
เม่ือผใู ชก ดแลวเราจะแสดงวนั และเวลาเปนภาษาไทยใน text field ดา นบน และถา กดปมุ
ทางขวาเรากจ็ ะแสดงวันและเวลาเปน ภาษาองั กฤษใน text field ดานลาง และเราจะทําการลาง
text field ท้ังสองเม่ือผูใชก ดปุม clear
การกาํ หนดใหม ีการใช border layout นนั้ ทาํ ไดดว ยการเรียก
setLayout(new BorderLayout());
การนํา object เขาไปใสไวในตําแหนง ตา ง ๆ ก็ทาํ ไดดว ยการกาํ หนดตาํ แหนง ของ object นน้ั ๆ
เชน
add(clearButton, BorderLayout.CENTER);
add(northOutput, BorderLayout.NORTH);
add(southOutput, BorderLayout.SOUTH);
add(leftButton, BorderLayout.WEST);
add(rightButton, BorderLayout.EAST);
text filed เปนชอ งทางท่ี Swing เอาไวใชร บั ขอ มลู และแสดงขอมูลใหกับผใู ช ในโปรแกรม
ตัวอยางของเรา เราสราง text field สองตวั สาํ หรบั แสดงขอ มลู เทา น้นั คอื northOutput และ
southOutput
northOutput = new JTextField(25);
northOutput.setFont(new Font("Serif", Font.BOLD, 14));
northOutput.setHorizontalAlignment(JTextField.CENTER);
northOutput.setEditable(false);
southOutput = new JTextField(25);
southOutput.setFont(new Font("Serif", Font.BOLD, 14));
southOutput.setHorizontalAlignment(JTextField.CENTER);
southOutput.setEditable(false);
ในการแสดงผลลัพธนัน้ เรากําหนดใหขอ ความปรากฏในตาํ แหนงกึ่งกลางของ text field ดว ยการ
เรียกใช method setHorizontalAlignment(JTextField.CENTER) พรอ มท้งั กําหนดใหผใู ชไ ม
สามารถทําการเปลีย่ นแปลงขอ ความใน text field ไดด วยการเรยี กใช method setEditable()
ดว ยคา false
ในการฟงเหตกุ ารณท่อี าจเกิดข้ึนในโปรแกรมตวั อยา งของเรานนั้ เราตอ งตรวจสอบดวู าระหวาง
ปุมสามปมุ ปมุ ไหนถูกกด (ทาํ ใหเกดิ action event) โดยเราตองตรวจสอบเหตุการณเ หลา นใ้ี น
347
เร่ิมตนการเขยี นโปรแกรมดว ย Java intro. to Java (FEU.faa)
method actionPerformed() อยสู องเหตกุ ารณ คือเมื่อปมุ rightButton ถกู กดหรือปมุ
leftButton ถูกกด สว นปุม clearButton นน้ั เราทาํ ในอีกรปู แบบหนงึ่ ซ่งึ เราจะไดอธบิ ายตอ ไป
public void actionPerformed(ActionEvent e) {
Date today;
String dateOut;
DateFormat dateFormatter;
if(e.getSource() == leftButton) {
//create a Thai locale
Locale thLocale = new Locale("th", "TH");
//set date and time format with a given locale above
dateFormatter = DateFormat.getDateTimeInstance(
DateFormat.LONG, DateFormat.LONG, thLocale);
//get today's date
today = new Date();
dateOut = dateFormatter.format(today);
//send date and time to output
northOutput.setText(dateOut);
}
if(e.getSource() == rightButton) {
//set default locale to US
Locale.setDefault(new Locale("us", "US"));
//set date and time format with a given locale above
dateFormatter = DateFormat.getDateTimeInstance(
DateFormat.LONG, DateFormat.SHORT);
//get today's date
today = new Date();
dateOut = dateFormatter.format(today);
//send date and time to output
southOutput.setText(dateOut);
}
}
เราตรวจสอบวา ปมุ ไหนถกู กดจาก parameter e ทีส่ งเขามายงั method actionPerformed()
ดวยการเรยี กใช method getSource() ซึ่งถา แหลงที่มาของเหตกุ ารณเ ปนอยา งใดอยางหนึง่
ระหวา ง rightButton และ leftButton เราก็จะกําหนดการสนองตอบตอ เหตกุ ารณนั้น ๆ เชนถา
ปมุ rightButton ถูกกดเราก็แสดงวนั และเวลาดวย format ที่กําหนดไวสาํ หรบั ประเทศ
สหรฐั อเมรกิ า ซ่งึ เรากําหนดจาก locale ดวยการกาํ หนดคา default ใหเ ปน ไปตามขอ กําหนด
ของประเทศสหรฐั อเมริกา
Locale.setDefault(new Locale("us", "US"));
[สาเหตุท่เี ราตอ งกาํ หนดใหเปน default กเ็ พราะวามนั อาจถกู เปลย่ี นจากการกดปมุ leftButton
ของผใู ช]
สําหรับการแสดงขอ ความเราก็ใชการเรยี ก method setText() เชน เดียวกนั กบั โปรแกรมตัวอยาง
กอ นหนา นี้ เพียงแตว า เราตอ งเรยี กใช text field ท่ีถกู ตองตามการกาํ หนดของเราวาตวั ไหนจะ
แสดงเมื่อปมุ ไหนถกู กด
สว นการ clear ขอความใน text field ทง้ั สองเราเลอื กท่จี ะเขยี น code ณ เวลาที่เราสรางปมุ
พรอม ๆ กันไป
clearButton = new JButton("Clear");
clearButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
northOutput.setText("");
southOutput.setText("");
}
});
และการ clear กเ็ ปนเพียงแคการกาํ หนดใหข อ ความใน text field ทัง้ สองเปน null เทา น้นั เอง
และผลลพั ธท ่ีเราไดจ ากการกดปมุ ทัง้ สองกม็ ดี ังนี้
348
บทท่ี 11: GUI และ Event Handling intro. to Java (FEU.faa)
ภาพท่ี 11.3 ผลลพั ธของการกดปมุ TH Time และปมุ US Time
ผูอานจะเหน็ วาการใช border layout นัน้ ทาํ ใหเราสามารถกาํ หนดตําแหนง ของ object ไดแต
ทวามันกย็ ังไมคอยจะสมบรณู เ ทาใดนกั ถา สงั เกตใหด ผี ูอานก็จะเหน็ วาปุมทอ่ี ยูในตาํ แหนง
CENTER นัน้ จะมขี นาดใหญกวา ปุมอ่ืน ๆ ท้งั นก้ี เ็ พราะวา border layout manager จะวาง
สวนประกอบในตําแหนงอื่นกอ น แลว จงึ วาง object ในตาํ แหนง CENTER เปน ตวั สดุ ทา ย พรอม
กบั เพิ่มขนาดให object ทีอ่ ยใู นตาํ แหนง นีโ้ ดยอัตโนมตั ิจนเต็มเนื้อที่ ซึ่งเนอื้ ท่ีท่วี า นั้นมาจากการ
กําหนดให text filed มีความจตุ ามจาํ นวนของตัวอกั ษรที่กาํ หนดไว (เชน 25 ในโปรแกรม
ตวั อยาง) ถาเราทาํ การขยายหรือลดขนาดของ window เราก็จะเหน็ วาขนาดของ object ที่อยู
สวนรมิ จะไมเปลี่ยนขนาด สวนที่เปลย่ี นกค็ อื object ท่อี ยูในตําแหนง CENTER
และ code ทั้งหมดของโปรแกรม BorderLayoutApp.java ก็มดี งั น้ี
1: /**
2: Date and Time with Border Layout
3: */
4:
5: import javax.swing.*;
6: import java.awt.*;
7: import java.awt.event.*;
8: import java.util.*;
9: import java.text.*;
10:
11: class BorderLayoutApp {
12: public static void main(String[] args) {
13: JFrame.setDefaultLookAndFeelDecorated(true);
14: JFrame frame = new DateAndTimeFrame();
15: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
16: frame.setVisible(true);
17: }
18: }
19:
20: class DateAndTimeFrame extends JFrame {
21: private static final int WIDTH = 400;
22: private static final int HEIGHT = 110;
23:
24: //create a frame and a panel
25: public DateAndTimeFrame() {
26: setTitle("Date and Time");
27: setSize(WIDTH, HEIGHT);
28: JPanel panel = new DateAndTimePanel();
29: add(panel);
30: }
31: }
32:
33: class DateAndTimePanel extends JPanel implements ActionListener {
34: protected JButton leftButton, rightButton, clearButton;
35: protected JTextField northOutput, southOutput;
36:
37: public DateAndTimePanel() {
38: //get image icon for the button
39: ImageIcon clockIcon = createImageIcon("clock.gif");
40: //create a button
41: rightButton = new JButton("US Time", clockIcon);
42: //set text position before icon
43: rightButton.setVerticalTextPosition(AbstractButton.CENTER);
44: rightButton.setHorizontalTextPosition(AbstractButton.LEADING);
45: //alt/u key activation
349
เริ่มตน การเขียนโปรแกรมดว ย Java
46: rightButton.setMnemonic(KeyEvent.VK_U); intro. to Java (FEU.faa)
//add a listener to this button
47: rightButton.addActionListener(this);
48:
49: //create a button
leftButton = new JButton("TH Time", clockIcon);
50: //set text position before icon
51: leftButton.setVerticalTextPosition(AbstractButton.CENTER);
leftButton.setHorizontalTextPosition(AbstractButton.TRAILING);
52: //alt/t key activation
53: leftButton.setMnemonic(KeyEvent.VK_T);
54: //add a listener to this button
leftButton.addActionListener(this);
55:
56: //add a button to clear north and south text fields
57: clearButton = new JButton("Clear");
clearButton.addActionListener(new ActionListener() {
58:
59: public void actionPerformed(ActionEvent e) {
60: northOutput.setText("");
61: southOutput.setText("");
62:
63: }
64: });
65:
66: //create output label fro us locale
67: northOutput = new JTextField(25);
68: northOutput.setFont(new Font("Serif", Font.BOLD, 14));
69: northOutput.setHorizontalAlignment(JTextField.CENTER);
70: northOutput.setEditable(false);
71:
72: //create output label for thai lacale
73: southOutput = new JTextField(25);
74: southOutput.setFont(new Font("Serif", Font.BOLD, 14));
75: southOutput.setHorizontalAlignment(JTextField.CENTER);
76: southOutput.setEditable(false);
77:
78: //set layout to BorderLayout
79: setLayout(new BorderLayout());
add(clearButton, BorderLayout.CENTER);
80: add(northOutput, BorderLayout.NORTH);
81: add(southOutput, BorderLayout.SOUTH);
add(leftButton, BorderLayout.WEST);
82: add(rightButton, BorderLayout.EAST);
}
83:
84: //get image icon file
protected static ImageIcon createImageIcon(String path) {
85:
//get a path containing this image
86: java.net.URL imgURL = BorderLayoutApp.class.getResource(path);
87: if (imgURL != null) {
88: return new ImageIcon(imgURL);
} else {
89:
90: System.err.println("Couldn't find file: " + path);
return null;
91: }
92: }
93: //display date and time when button is clicked or alt/t is activated
public void actionPerformed(ActionEvent e) {
94: Date today;
95: String dateOut;
DateFormat dateFormatter;
96:
if(e.getSource() == leftButton) {
97: //create a Thai locale
98: Locale thLocale = new Locale("th", "TH");
//set date and time format with a given locale above
99: dateFormatter = DateFormat.getDateTimeInstance(
DateFormat.LONG, DateFormat.LONG, thLocale);
100: //get today's date
101: today = new Date();
102: dateOut = dateFormatter.format(today);
103:
104: //send date and time to output
105: northOutput.setText(dateOut);
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
350
บทท่ี 11: GUI และ Event Handling
120: }
121:
122: if(e.getSource() == rightButton) {
123: //set default locale to US
124: Locale.setDefault(new Locale("us", "US"));
125: //set date and time format with a given locale above
126: dateFormatter = DateFormat.getDateTimeInstance(
127: DateFormat.LONG, DateFormat.SHORT);
intro. to Java (FEU.faa)
128: //get today's date
129: today = new Date();
130: dateOut = dateFormatter.format(today);
131:
132: //send date and time to output
133: southOutput.setText(dateOut);
134: }
135: }
136: }
11.2.2 Grid layout
การจดั วางที่เราทาํ นั้นยงั มีขอ ดอ ยอยพู อสมควร เชน ปุมจะขยายตวั จนเตม็ ทอี่ ยู ถา หากเรา
ตอ งการปมุ เพิม่ ขึน้ แตต อ งการใหอยู ณ ตาํ แหนง เดียวกนั เราจะทํายังไง คําตอบก็คอื ใช panel
เขา มาชวย นนั่ ก็คอื จดั วางปุมใหอ ยใู นตาํ แหนง ทีต่ อ งการใน panel แลว จึงจดั วาง panel ใน
frame อกี ที (หรอื แมกระทัง่ panel ใน panel)
โปรแกรม SimpleCalculator.java เปนโปรแกรมตัวอยา งท่ีเราใชท ้งั panel และการจัดวาง
object ดวย grid layout เขา มาชว ย ภาพที่ 11.4 แสดงหนา ตา งท่ีเราสรางขึ้น
JPanel ใช
BorderLayout เพ่ือวาง
JTextField และ JPanel
JTextField สาํ หรับแสดงผล
(BorderLayout.NORTH)
JPanel ใช GridLayout
สําหรบั วางปมุ ตาง ๆ
(BorderLayout.CENTER)
ภาพที่ 11.4 การจัดวาง component ดวย Grid layout และ Border layout
การจัดวาง component ของเราใช JFrame อยหู นงึ่ ตัวทเี่ ปน container หลกั ของ component
อ่ืน เราใช Jpanel สองตวั ตัวแรกใชส าํ หรบั การจัดวาง JTextField และ JPanel ท่ใี ชจ ดั วางปมุ
ตา ง ๆ โดยเราไดก าํ หนดให JTextField อยูดาน NORTH สว น JPanel ที่เกบ็ ปุม อยูท ี่ CENTER
สําหรับ JPanel อกี ตัวเราใชเ กบ็ component ทง้ั สองเพ่ือนาํ ไปเก็บไวใน JFrame ตอไป
การใช GridLayout ก็ทําไดดงั นี้
panel = new JPanel(new GridLayout(5, 4, 2, 2));
จากประโยคทเ่ี ห็นเรากําหนดให JPanel เรียกใช GridLayout ที่มจี าํ นวนเทา กับ 5 x 4 (5 แถว 4
column) สวนตวั เลข 2 สองตวั ทเ่ี หน็ เปน การกาํ หนดชองวางระหวา งปมุ ทอี่ ยูใน grid layout วา
ควรจะหา งกันสองหนว ย (pixel) หลังจากท่ีเรากาํ หนด layout แลวเราก็นาํ ปมุ ตา ง ๆ เขาสู panel
น้ี
351
เรมิ่ ตน การเขียนโปรแกรมดว ย Java
for(int i = 0; i < labels.length; i++) { intro. to Java (FEU.faa)
JButton button = new JButton(labels[i]);
button.addActionListener(this);
if(i == 3)
button.setForeground(Color.RED);
button.setFont(f);
panel.add(button);
}
โดยเราไดสรา ง array สาํ หรบั เกบ็ ขอ มูลทต่ี องอยบู นปมุ ไวด งั นี้
String[] labels = { "\u221a", "x\262", "\261", "C",
"7", "8", "9", "+",
"6", "5", "4", "-",
"1", "2", "3", "*",
"0", ".", "=", "/" };
ขอมูลทีป่ รากฏอยบู นปมุ สามตวั แรกเราใชตวั อักษร Unicode เปนตัวกาํ หนดซ่งึ มีคาเปน
เคร่ืองหมาย √ x2 และ ± ตามลาํ ดับ เรายงั ไดก ําหนดใหตวั อักษร C บนปมุ สําหรบั การลา ง
ขอความใน text field เปน สีแดงดวยการเรยี กใช method setForeground(Color.RED) บนปมุ
นี้ พรอมกันนเ้ี ราไดก าํ หนด font ใหก บั ปุม เหลานีด้ วยเชน กนั
ระหวา งการสรางปุมเรากท็ าํ การเพ่ิมความสามารถในการฟงเหตกุ ารณใ หกบั ปุมตาง ๆ หากมกี าร
กดเกดิ ขนึ้ เหมือนเชน ทเี่ ราทาํ กอนหนานี้
การใช panel หลาย ๆ ตวั ในการจัดวาง component ดวย layout ท่ตี า งกนั จะทาํ ใหหนา ตาของ
หนา ตา งทเี่ ราสรางขน้ึ มคี วามเปนระเบยี บมากขน้ึ ยิ่งความหลากหลายและจาํ นวนของ
component มีมากเทาไรการใช layout manager ก็มีสว นชว ยใหก ารจดั วางเปนไปไดดยี ง่ิ ข้ึน
สําหรับ code ของการสนองตอบตอ การกระทาํ ของผูใชกไ็ มซ บั ซอนเทาไรนกั เรายอมเฉพาะการ
กดปุม ที่อยใู นหนาตา งเทานัน้ การกดปมุ ตวั เลขบน keyboard ยังไมมผี ลใด ๆ ตอเครือ่ งคิดเลข
ของเรา
public void actionPerformed(ActionEvent e) {
//get action command
String action = e.getActionCommand();
//handle operation clear
if(action.equals("C")) {
screen.setText("0");
op = "";
reg1 = reg2 = 0;
overWrite = true;
return;
}
//handle + or -
if(action.equals("\261")) {
String s = screen.getText();
if(s.startsWith("-")) {
screen.setText(s.substring(1));
}
else
screen.setText("-" + s);
return;
}
//handle fraction
if(action.equals(".")) {
if(overWrite) {
screen.setText(action);
overWrite = false;
return;
}
String s = screen.getText();
if(s.indexOf('.') != -1)
return;
s += '.';
352
บทที่ 11: GUI และ Event Handling intro. to Java (FEU.faa)
screen.setText(s);
}
//handle digits 0 - 9
if(action.equals("0") || action.equals("1") || action.equals("2") ||
action.equals("3") || action.equals("4") || action.equals("5") ||
action.equals("6") || action.equals("7") || action.equals("8") ||
action.equals("9")) {
if(overWrite)
screen.setText(action);
else
screen.setText(screen.getText() + action);
overWrite = false;
}
//handle operators
if(action.equals("+") || action.equals("-") ||
action.equals("*") || action.equals("/") || action.equals("=")) {
reg2 = Double.parseDouble(screen.getText());
reg1 = calc(op, reg1, reg2);
screen.setText("" + reg1);
op = action;
overWrite = true;
}
//handle square root
if(action.equals("\u221a")) {
double result = Math.sqrt(Double.parseDouble(screen.getText()));
screen.setText(String.valueOf(result));
}
//handle x square
if(action.equals("x\262")) {
double result = Double.parseDouble(screen.getText());
result *= result;
screen.setText(String.valueOf(result));
}
}
และ code สวนอ่ืน ๆ ท้งั หมดของโปรแกรม SimpleCalculator.java ก็มดี ังนี้
1: /**
2: Simple calculator
3: */
4:
5: import javax.swing.*;
6: import java.awt.*;
7: import java.awt.event.*;
8: import java.util.*;
9: import java.text.*;
10:
11: class SimpleCalculator {
12: public static void main(String[] args) {
13: JFrame.setDefaultLookAndFeelDecorated(true);
14: JFrame frame = new CalculatorFrame();
15: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
16: frame.setVisible(true);
17: }
18: }
19:
20: class CalculatorFrame extends JFrame {
21:
22: //create a frame and a panel
23: public CalculatorFrame() {
24: setTitle("Simple Calculator");
25: JPanel panel = new CalculatorPanel();
26: add(panel);
27: pack();
28: }
29: }
30:
31:
32: class CalculatorPanel extends JPanel implements ActionListener {
353
เร่ิมตน การเขยี นโปรแกรมดว ย Java
33: private JTextField screen; intro. to Java (FEU.faa)
private JPanel panel;
34: private String[] labels = {"\u221a", "x\262", "\261", "C",
35:
36: "7", "8", "9", "+",
"6", "5", "4", "-",
37: "1", "2", "3", "*",
38: "0", ".", "=", "/"};
private String op;
39: private double reg1, reg2;
40: private boolean overWrite;
41:
42: public CalculatorPanel() {
43: //use border layout for this panel
44: setLayout(new BorderLayout());
45:
46: //use grid layout for button panel
47: panel = new JPanel(new GridLayout(5, 4, 2, 2));
48: screen = new JTextField(15);
49: screen.setHorizontalAlignment(JTextField.RIGHT);
50: screen.setFont(new Font("SanSerif", 1, 16));
51: screen.setEditable(false);
52: screen.setText("0");
53: screen.setBackground(Color.white);
54:
55: //add component to this panel
56: add(screen, BorderLayout.NORTH);
57: add(panel, BorderLayout.CENTER);
58:
59: //create buttons
60: createButtons();
61:
62: op = "";
63: overWrite = true;
64: }
65:
66: //create buttons
private void createButtons() {
67:
68: Font f = new Font("Dialog", 1, 14);
for(int i = 0; i < labels.length; i++) {
69:
JButton button = new JButton(labels[i]);
70: button.addActionListener(this);
71: if(i == 3)
72: button.setForeground(Color.RED);
button.setFont(f);
73: panel.add(button);
74: }
}
75:
public void actionPerformed(ActionEvent e) {
76: //get action command
77: String action = e.getActionCommand();
78: //handle operation clear
79: if(action.equals("C")) {
80: screen.setText("0");
op = "";
81: reg1 = reg2 = 0;
82: overWrite = true;
return;
83: }
84: //handle + or -
85: if(action.equals("\261")) {
86: String s = screen.getText();
if(s.startsWith("-")) {
87:
88: screen.setText(s.substring(1));
89: }
90: else
91:
92: screen.setText("-" + s);
93: return;
94: }
95:
96: //handle fraction
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
354
บทที่ 11: GUI และ Event Handling
107: if(action.equals(".")) { intro. to Java (FEU.faa)
if(overWrite) {
108: screen.setText(action);
109: overWrite = false;
return;
110: }
String s = screen.getText();
111: if(s.indexOf('.') != -1)
112: return;
s += '.';
113: screen.setText(s);
114:
}
115:
//handle digits 0 - 9
116: if(action.equals("0") || action.equals("1") || action.equals("2") ||
117:
action.equals("3") || action.equals("4") || action.equals("5") ||
118: action.equals("6") || action.equals("7") || action.equals("8") ||
action.equals("9")) {
119:
120: if(overWrite)
screen.setText(action);
121:
else
122: screen.setText(screen.getText() + action);
123:
overWrite = false;
124: }
125: //handle operators
126: if(action.equals("+") || action.equals("-") ||
127: action.equals("*") || action.equals("/") || action.equals("=")) {
128: reg2 = Double.parseDouble(screen.getText());
reg1 = calc(op, reg1, reg2);
129: screen.setText("" + reg1);
op = action;
130: overWrite = true;
131:
}
132:
//handle square root
133: if(action.equals("\u221a")) {
134:
double result = Math.sqrt(Double.parseDouble(screen.getText()));
135: screen.setText(String.valueOf(result));
}
136:
137: //handle x square
if(action.equals("x\262")) {
138:
double result = Double.parseDouble(screen.getText());
139: result *= result;
140: screen.setText(String.valueOf(result));
}
141: }
142:
//handle operations +, -, * and /
143: private double calc(String op1, double r1, double r2) {
144: if(op.equals("+"))
145: r1 = r1 + r2;
146: else if(op.equals("-"))
r1 = r1 - r2;
147:
148: else if(op.equals("*"))
r1 = r1 * r2;
149:
else if(op.equals("/"))
150: r1 = r1 / r2;
151:
else
152: r1 = r2;
153:
return r1;
154: }
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170: }
[การกาํ หนดการทาํ งานของปมุ ในเครอ่ื งคิดเลข]
โปรแกรมเครือ่ งคดิ เลขทเี่ ราเขยี นขน้ึ ใช method actionPerformed() ในการจัดการกบั
เหตุการณทีเ่ กดิ ขึน้ จากการกดปมุ ทมี่ อี ยูในหนาตางของเครอื่ ง การทีจ่ ะทําใหผ ใู ชส ามารถใชป มุ ที่
มอี ยบู น keyboard ในการใสต วั เลขหรอื เครื่องหมายประมวลผลนน้ั เราตอ งใชก ระบวนการดกั ฟง
เหตุการณทม่ี าจาก class KeyEvent ดวยการเรียกใช method keyPressed(), keyReleased()
355
เร่มิ ตน การเขียนโปรแกรมดว ย Java intro. to Java (FEU.faa)
หรอื keyTyped() ซ่ึงในกรณขี องเรา method keyTyped() เปน method ทีเ่ หมาะสมทส่ี ดุ ท้งั นี้
ก็เนื่องจากวาเราสนใจเฉพาะการกดปุม จากผใู ชเ ทา นนั้
อยางไรก็ตามเราตอ งเขียน method ท้งั สามตัวไว (ขอ บังคบั ของ Java) แตจ ะใส code เฉพาะ
method keyTyped() เทานัน้ และ code ทีอ่ ยภู ายใน method นีก้ ็คลายกบั ท่เี ราใสไวใน
method actionPerformed()
กอ นทจ่ี ะเขยี น code ของ method keyTyped() เราตอง implements interface KeyListener
เชนเดยี วกับทีเ่ รา implements interface ActionListener ตอนท่เี ราเขยี น code สําหรับ
method actionPeformed()
class CalculatorPanel extends JPanel implements ActionListener, KeyListener {
เน่อื งจากวาเราตอ งดกั ฟง เหตกุ ารณท ่ีเกิดจากการกดปมุ พรอ มกบั การสง สิ่งท่ีปุมที่ถูกกดจากผูใ ช
ไปยงั text field เพอื่ แสดงผล เราตอ งกําหนดให text field คอยฟงเหตกุ ารณจาก keyboard
ดวย
screen.addKeyListener(this);
เชนเดียวกนั ปุมตา ง ๆ ที่เราสรา งขึ้นกต็ อ งคอยฟง การกดปุมดวยเหมอื นกัน เราจึงใสต วั ฟง
เหตุการณห ลังจากท่เี ราสรา งปุม เหลานีภ้ ายใน for/loop เชน เดยี วกบั ทเี่ ราทําเมือ่ ฟง action ที่
เกิดขึ้นจากการกดปมุ ทมี่ ีอยใู นหนาตา งดว ย mouse
for(int i = 0; i < labels.length; i++) {
JButton button = new JButton(labels[i]);
button.addActionListener(this);
button.addKeyListener(this);
if(i == 3)
button.setForeground(Color.RED);
button.setFont(f);
panel.add(button);
}
ในการแยกแยะปมุ ทผี่ ูใชกดน้นั เราจะใช method getKeyChar() เปน ตัวอา นคาปมุ กอ น หลงั จาก
นัน้ เราจงึ ตรวจสอบคาของปุมท่ถี กู กดวา เปน ปมุ ตัวไหนดว ยการเปรยี บเทยี บกบั คาทไี่ ดต ้งั ไว
สําหรับปุมเหลา น้นั
ภายใน method keyTyped() เราจะคอยฟง KeyEvent ทเ่ี กิดขึ้นวา เกดิ จากปมุ ใดดว ยการเรยี ก
method getKeyChar() ผานทาง parameter KeyEvent: e นี้ คาท่ีสง กลบั มาจาก method
getKeyChar() จะเปน คา Unicode ของปุมทถ่ี ูกกดนน้ั
public void keyTyped(KeyEvent e) {
char c = e.getKeyChar();
switch(c) {
//'0' .. '9'
case 48: case 49: case 50: case 51:
case 52: case 53: case 54: case 55:
case 56: case 57:
if(overWrite)
screen.setText("" + c);
else
screen.setText(screen.getText() + c);
overWrite = false;
break;
//'*', '+', '-', '/', '\n', '='
case 42: case 43: case 45:
case 47: case 61: case 10:
reg2 = Double.parseDouble(screen.getText());
reg1 = calc(op, reg1, reg2);
screen.setText("" + reg1);
op = "" + c;
overWrite = true;
break;
//'.'
case 46:
356
บทที่ 11: GUI และ Event Handling
if(overWrite) { intro. to Java (FEU.faa)
screen.setText("" + c);
overWrite = false;
return;
}
String s = screen.getText();
if(s.indexOf('.') != -1)
return;
s += '.';
screen.setText(s);
break;
//'C', 'c'
case 67: case 99:
screen.setText("0");
op = "";
reg1 = reg2 = 0;
overWrite = true;
return;
default: return;
}
}
เนอ่ื งจากวา ตวั แปร op เกบ็ คา ทเ่ี ปน String ดงั นั้นการนําคา จากตัวแปร c ไปเก็บใน op จึงตอ ง
เปล่ยี นตัวแปร c ใหเปน String ดว ยการบวกเขา กบั null String ("") เชน op = "" + c; เปน ตน
การ run โปรแกรมกเ็ หมอื นเดิมแตผ ใู ชสามารถใชไ ดท ้งั การกดปุมผา นทาง keyboard และผาน
ทางการกดปุมในหนา ตา ง
11.3 JRadioButton และ JComboBox
ภาพที่ 11.5 แสดงผลลพั ธข องโปรแกรมท่ใี ช JRadioButton และ JCombobox
JRadioButton JComboBox
JPanel:
topPanel ทีใ่ ช
เกบ็
JRadioButton 2
ตัว
JLabel ทใ่ี ช BorderFactory กาํ หนด line และ title ใช
สาํ หรบั แสดง date/time ตามท่ีผูใชเลือก
ภาพท่ี 11.5 Swing application ทใี่ ช JRadioButton, JComboBox และ TitledBorder
โปรแกรมตัวนี้ใช panel 2 ตัวในการจดั วาง component ในหนา ตาง ตวั แรกเปน panel
(toppanel) ทีใ่ ชเก็บ radio button (thai และ us) และ combo box (patterns) ตัวทสี่ องเปน
panel หลกั ทีใ่ ชเก็บ panel ตวั แรกและ label (result) ที่ใชส ําหรบั แสดงผลลพั ธ เราสราง radio
button ดว ยคาํ ส่งั
thai = new JRadioButton("THAI");
thai.setMnemonic(KeyEvent.VK_T);
thai.setActionCommand("THAI");
thai.setSelected(true);
us = new JRadioButton("US");
us.setMnemonic(KeyEvent.VK_U);
us.setActionCommand("US");
357
เริม่ ตนการเขยี นโปรแกรมดว ย Java intro. to Java (FEU.faa)
เรากําหนดใหตวั แปร thai และ us มาจาก class JRadioButton โดยเรากําหนดขอมลู ของตวั
แปรท้ังสองตวั ผานทาง constructor ดวยคา "THAI" และ "US" ตามลาํ ดบั ปุม ทงั้ สองยอมให
ผใู ชสามารถใช keyboard: ALT+T สาํ หรบั การแสดงผลท่ีเปน ภาษาไทย และ ALT+U สําหรบั
ผลลัพธท ่ีเปน ภาษาอังกฤษ และเราจะกาํ หนดใหปุม ไทยเปน ปมุ ท่ถี กู เลือกโดยอตั โนมตั ทิ กุ คร้งั ท่ี
โปรแกรมถูก execute
การกําหนดตวั ดกั ฟง event ของ radio button ท้งั สองก็ทําผานการกาํ หนดดวย method
addActionListener() เชนเคย
เน่อื งจากวา เราตอ งการใหปมุ ใดปมุ หนึง่ (ปุม เดียวเทานัน้ ) ถกู เลอื ก เราจงึ ตองใช ButtonGroup
เปน ตวั กําหนด (เชน เดยี วกนั ถา โปรแกรมตองการใหมีการเลอื กไดม ากกวา หนึง่ ปุม เรากไ็ มต อ ง
ใช ButtunGroup)
ButtonGroup group = new ButtonGroup();
group.add(thai);
group.add(us);
เม่ือเราได component ทั้งสองแลวเราก็นาํ component ท้ังสองเขา สู panel ตอ ไปโดยเราจะจดั
วางดวย grid layout ทมี่ ีขนาดเทากบั 1 x 2
radioPanel = new JPanel(new GridLayout(1, 2));
radioPanel.add(thai);
radioPanel.add(us);
ข้นั ตอนตอ ไปทเี่ ราตองทํากค็ อื การสรา ง combo box สาํ หรบั กําหนดหนาตา (patterns) ของวนั
และเวลาทผ่ี ใู ชส ามารถเลือกได
patterns = new JComboBox(patternStrings);
patterns.setEditable(true);
patterns.addActionListener(this);
โดยเราจะกาํ หนดใหห นาตาของวนั และเวลาเปน string ท่ี Java ไดก าํ หนดไว
String[] patternStrings = {
"dd MMMMM yyyy",
"dd.MM.yy",
"MM/dd/yy",
"yyyy.MM.dd G 'at' hh:mm:ss z",
"EEE, MMM d, ''yy",
"h:mm a",
"H:mm:ss:SSS",
"K:mm a,z",
"yyyy.MMMMM.dd GGG hh:mm aaa"
};
พรอ มกนั นเ้ี รายงั ไดเปดโอกาสใหผ ใู ชส ามารถใส pattern เขาสู combo box ไดดวยการกาํ หนด
setEditable(true) บน combo box น้ี หลังจากน้นั เราก็นาํ topPanel และ patterns เขา ไปเก็บ
ไวใ น panel
topPanel.add(radioPanel);
topPanel.add(patterns);
ส่งิ ทเ่ี ราตองทําตอ ก็คอื การสราง label สําหรบั การแสดงผล
result = new JLabel(" ");
result.setForeground(Color.blue);
result.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createLineBorder(Color.LIGHT_GRAY), "Current Date/Time",
TitledBorder.LEFT, TitledBorder.TOP
));
เรากาํ หนดใหส ขี องตัวหนงั สือท่ตี องแสดงผา น label เปน สนี าํ้ เงินพรอ มท้ังกาํ หนดเสน กรอบของ
label เปน เสนสเี ทา (light gray) ทม่ี ีการกําหนด title: "Current Date/Time" ใหอยู ณ
ตาํ แหนงบนซา ย หลงั จากนน้ั เรากน็ ํา component ท้ังสองเขา สู panel หลกั ของเรา
358
บทท่ี 11: GUI และ Event Handling intro. to Java (FEU.faa)
add(topPanel, BorderLayout.CENTER);
add(result, BorderLayout.SOUTH);
กระบวนการตอ ไปก็คือการสนองตอบตอ event ทเ่ี กดิ ขึน้ จากการเลอื กของผใู ช น่ันก็คอื เราตอง
เขยี น code ภายใน method actionPerformed()
public void actionPerformed(ActionEvent e) {
//THAI radio button is checked
if(e.getSource() == thai) {
Locale.setDefault(new Locale("th", "TH"));
String newSelection = (String)patterns.getSelectedItem();
pattern = newSelection;
reformat();
}
//US radio button is checked
if(e.getSource() == us) {
Locale.setDefault(new Locale("us", "US"));
String newSelection = (String)patterns.getSelectedItem();
pattern = newSelection;
reformat();
}
//item in combo box is selected
if(e.getSource() == patterns) {
String newSelection = (String)patterns.getSelectedItem();
pattern = newSelection;
reformat();
}
}
โปรแกรมของเราใช object จาก JRadioButton 2 ตัวและจาก JComboBox 1 ตัวดังนั้นเราจึง
ตอ งตรวจสอบดวู า object ท้ังสามตวั นน้ั ตัวไหนถูกเลือก (fire an event) เรากําหนดใหปมุ thai
เปน ปุมท่ไี ดรับการกําหนดคาจากโปรแกรม (default) เพราะฉะนัน้ คา ของ locale ที่เราไดจ าก
การ run โปรแกรมจะเปนการแสดงผลลัพธดว ยภาษาไทย ทั้งนีท้ งั้ น้นั จะตอ งมี event ใด event
หนงึ่ เกิดขน้ึ กอน การตรวจสอบ event ทั้งหมดมอี ยสู ามสว นคอื
1. ปุม thai ถกู กด ถาปุม น้ถี ูกเลอื กเราจะกําหนดให locale ของเคร่ืองเปน ภาษาไทย ดงึ คา
pattern ออกจาก combo box ดว ย method getSelectedItem() ใชคานสี้ ําหรบั การ
แสดงผลใน method reformat()
2. ปมุ us ถูกกด ถาปมุ นี้ถกู เลอื กเราจะกาํ หนดให locale ของเครอ่ื งเปน ภาษาอังกฤษ ดึง
คา pattern ออกจาก combo box ดวย method getSelectedItem() ใชคา นีส้ าํ หรบั
การแสดงผลใน method reformat()
3. item ตัวใดตวั หนง่ึ ใน combo box ถกู เลอื ก เรากด็ งึ เอา pattern นั้นสง ไปให method
reformat() เพ่ือแสดงผลตอ ไป
method reformat() ใช pattern ทผี่ ูใชเลือกเปน ตวั กาํ หนดรปู แบบของการแสดงผลของวนั
เวลาทถี่ ูกดึงออกจากเครอ่ื ง ณ เวลาทผี่ ูใชเลอื ก
private void reformat() {
//gets today's date and format it with selected pattern and locale
Date today = new Date();
SimpleDateFormat formatter = new SimpleDateFormat(
pattern, Locale.getDefault());
try {
String dateString = formatter.format(today);
result.setForeground(Color.BLACK);
result.setText(dateString);
}
catch (IllegalArgumentException ie) {
result.setForeground(Color.RED);
result.setText("Error: " + ie.getMessage());
}
}
359
เริม่ ตนการเขียนโปรแกรมดว ย Java
ภาพท่ี 11.6 JComboBox และ item ท่อี ยภู ายใน intro. to Java (FEU.faa)
หลังจากที่เลอื ก pattern ใน JComboBox แลวผลลัพธทเี่ ราไดคอื
ภาพท่ี 11.7 ตวั อยางผลลัพธข องโปรแกรม
ผอู านควรทดลอง run โปรแกรมตัวนดี้ ว ยการใส pattern เขา สู JComboBox แลวดผู ลลัพธว า
เปน อยางไร แตจ ะตอ งใช pattern ตามที่ Java ยอมใหม ีไดด ังทแี สดงในตารางท่เี หน็ น1้ี
ตวั อกั ษร วนั และเวลา การแสดงผล ตัวอยา ง
G Era designator Text AD
y Year Year 1996; 96
M Month in year Month July; Jul; 07
w Week in year Number 27
W Week in month Number 2
D Day in year Number 189
d Day in month Number 10
F Day of week in month Number 2
E Day in week Text Tuesday; Tue
a Am/pm marker Text PM
H Hour in day (0-23) Number 0
k Hour in day (1-24) Number 24
K Hour in am/pm (0-11) Number 0
h Hour in am/pm (1-12) Number 12
m Minute in hour Number 30
s Second in minute Number 55
S Millisecond Number 978
z Time zone General time zone Pacific Standard Time; PST; GMT-08:00
Z Time zone RFC 822 time zone -0800
Code ท้งั หมดของโปรแกรมตวั อยา งก็มีดังนี้
1 ผอู านควรศึกษาเพิ่มเติมจาก Java API ถึงการใชงานตัวอักษรตาง ๆ ในตาราง
360
บทที่ 11: GUI และ Event Handling
1: /**
2: Using JRadioButton, JComboBox and BorderFatory
3: */
4:
5: import javax.swing.*;
6: import javax.swing.border.*;
7: import java.awt.*; intro. to Java (FEU.faa)
8: import java.awt.event.*;
9: import java.util.*;
10: import java.text.*;
11:
12: class FormatDate {
13: public static void main(String[] args) {
14: JFrame.setDefaultLookAndFeelDecorated(true);
15: JFrame frame = new FormatDateFrame();
16: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
17: frame.setVisible(true);
18: }
19: }
20:
21: class FormatDateFrame extends JFrame {
22:
23: //create a frame and a panel
24: public FormatDateFrame() {
25: setTitle("Date and Time");
26: JPanel panel = new FormatDatePanel();
27: add(panel);
28: pack();
29: }
30: }
31:
32: //date and time panel
33: class FormatDatePanel extends JPanel implements ActionListener {
34: JPanel radioPanel; //radio buttons panel
35: JPanel topPanel; //panel for buttons and combo box
36: JRadioButton thai, us; //locales
37: JComboBox patterns; //patterns in combo box
38: JLabel result; //label displaying result
39: String pattern; //selected pattern
40: Locale locale; //default locale
41:
42: public FormatDatePanel() {
43: //layout for main panel
44: setLayout(new BorderLayout());
45:
46: //THAI radio button - default
47: thai = new JRadioButton("THAI");
48: thai.setMnemonic(KeyEvent.VK_T);
49: thai.setSelected(true);
50:
51: //US radio button
52: us = new JRadioButton("US");
53: us.setMnemonic(KeyEvent.VK_U);
54:
55: //logical grouping - to ensure that only
56: //one radio button is selected
57: ButtonGroup group = new ButtonGroup();
58: group.add(thai);
59: group.add(us);
60:
61: //add listeners to both buttons
62: thai.addActionListener(this);
63: us.addActionListener(this);
64:
65: //add both buttons to panel - one row, two columns
66: radioPanel = new JPanel(new GridLayout(1, 2));
67: radioPanel.add(thai);
68: radioPanel.add(us);
69:
70: //date patterns
71: String[] patternStrings = {
72: "dd MMMMM yyyy",
361
เริม่ ตนการเขยี นโปรแกรมดวย Java
73: "dd.MM.yy", intro. to Java (FEU.faa)
74: "MM/dd/yy",
75: "yyyy.MM.dd G 'at' hh:mm:ss z",
76: "EEE, MMM d, ''yy",
77: "h:mm a",
78: "H:mm:ss:SSS",
79: "K:mm a,z",
80: "yyyy.MMMMM.dd GGG hh:mm aaa"
81: };
82:
83: //panel contains radio buttons and combo box
84: //user can also edit item in the combo box
85: topPanel = new JPanel();
86: patterns = new JComboBox(patternStrings);
87: patterns.setEditable(true);
88: patterns.addActionListener(this);
89: topPanel.add(radioPanel);
90: topPanel.add(patterns);
91:
92: //displaying label with border and title
93: result = new JLabel(" ");
94: result.setForeground(Color.blue);
95: result.setBorder(BorderFactory.createTitledBorder(
96:
BorderFactory.createLineBorder(Color.LIGHT_GRAY),
97: "Current Date/Time",
98: TitledBorder.LEFT, TitledBorder.TOP
99: ));
100:
101: //add both panels to the main panel
102: add(topPanel, BorderLayout.CENTER);
103: add(result, BorderLayout.SOUTH);
104: }
105:
106: //performs action
107: public void actionPerformed(ActionEvent e) {
108:
109: //THAI radio button is checked
110: if(e.getSource() == thai) {
111:
112: Locale.setDefault(new Locale("th", "TH"));
113: String newSelection = (String)patterns.getSelectedItem();
114: pattern = newSelection;
115: reformat();
116: }
117: //US radio button is checked
118: if(e.getSource() == us) {
119: Locale.setDefault(new Locale("us", "US"));
120: String newSelection = (String)patterns.getSelectedItem();
121: pattern = newSelection;
122: reformat();
123: }
124: //item in combo box is selected
125: if(e.getSource() == patterns) {
126: String newSelection = (String)patterns.getSelectedItem();
127: pattern = newSelection;
128: reformat();
129: }
130: }
131:
132: //formats and displays today's date with either TH or US locale.
133: private void reformat() {
134:
135: //gets today's date and format it with selected pattern and locale
136: Date today = new Date();
137: SimpleDateFormat formatter = new SimpleDateFormat(
138:
139: pattern, Locale.getDefault());
140: try {
141:
142: String dateString = formatter.format(today);
143: result.setForeground(Color.BLACK);
144: result.setText(dateString);
145: } }
catch (IllegalArgumentException ie) {
result.setForeground(Color.RED);
result.setText("Error: " + ie.getMessage());
}
}
362
บทท่ี 11: GUI และ Event Handling
11.4 JCheckBox, JTextField และ JTextArea
โปรแกรมตัวอยา งท่จี ะแสดงใหด ตู อไปเปน โปรแกรมการใช JCheckBox และ JTextArea ในการ
นับจาํ นวนของคาํ (words) สระ (vowels) และ ชอ งวาง (spaces) ท่ีมีอยใู นประโยคทผ่ี ใู ชใ สเ ขา
สูโปรแกรม
JCheckBox in JPanel JTextField in JPanel intro. to Java (FEU.faa)
JButton in JPanel JTextArea
ภาพท่ี 11.8 JCheckBox, JTextField and JTextArea
จากภาพผลลพั ธจ ะเหน็ วา เราไดจ ัดวาง component ในตําแหนงตา ง ๆ ดว ยการใช panel เขามา
ชวย โปรแกรมตัวน้ีใช panel 4 ตัวในการวางองคประกอบดงั กลาว ตัวแรกใชจ ดั วาง JCheckBox
3 ตวั ตวั ทสี่ องใชจ ดั วาง JTextField 3 ตัว ตวั ท่ีสามใชจ ัดวาง JButton3 ตวั สวนตวั สดุ ทา ยใช
จดั วาง panel ท้ังสามตัวทกี่ ลา วถงึ กบั JTextArea ทอ่ี ยทู างดานขวา
เราเริ่มตน ดว ยการสรา ง JCheckBox 3 ตวั ช่ือ words, vowels และ spaces และ JPanel 1 ตวั ที่
ใชเกบ็ check box ท้ังสามตัวชอื่ cbPanel ดวยการกําหนดใหเ ปน grid layout: 3 x 1
words = new JCheckBox("Words");
words.addActionListener(this);
vowels = new JCheckBox("Vowels");
vowels.addActionListener(this);
spaces = new JCheckBox("Spaces");
spaces.addActionListener(this);
cbPanel = new JPanel(new GridLayout(3, 1));
cbPanel.add(words);
cbPanel.add(vowels);
cbPanel.add(spaces);
ตอมาเราก็สราง JTextField 3 ตวั เพ่อื เอาไวใชส ําหรบั แสดงผลทีห่ าได โดยจะกาํ หนดใหก าร
แสดงผลจาํ นวนนั้นอยูตรงกง่ึ กลางของ text field ท้ังสามตวั พรอ มทงั้ ใช JPanel เก็บ text field
ทงั้ สามดวยการใช grid layout: 3 x 1 ท่ีมชี อ งวา งระหวา ง component เทา กับ 2 pixel
wdCount = new JTextField(8);
wdCount.setEditable(false);
wdCount.setFont(font);
wdCount.setHorizontalAlignment(JTextField.CENTER);
vwCount = new JTextField(8);
vwCount.setEditable(false);
vwCount.setFont(font);
vwCount.setHorizontalAlignment(JTextField.CENTER);
spCount = new JTextField(8);
spCount.setEditable(false);
spCount.setFont(font);
spCount.setHorizontalAlignment(JTextField.CENTER);
363
เรม่ิ ตน การเขียนโปรแกรมดว ย Java intro. to Java (FEU.faa)
tfPanel = new JPanel(new GridLayout(3, 1, 2, 2));
tfPanel.add(wdCount);
tfPanel.add(vwCount);
tfPanel.add(spCount);
ขั้นตอนตอ ไปก็เปนการสรา งปมุ สาํ หรับการแสดงผล และปุม สาํ หรบั การออกจากโปรแกรม โดยจะ
กําหนดใหมีกรอบลอ มรอบปมุ ทง้ั สองไว พรอ มทงั้ ใช JPanel 1 ตัวเก็บปุมทง้ั สองไวด วย grid
layout: 1 x 2 ที่มีชองวา งเทา กับ 2 pixel เชนกนั
ok = new JButton("OK");
ok.addActionListener(this);
exit = new JButton("EXIT");
exit.addActionListener(this);
btPanel = new JPanel(new GridLayout(1, 2, 2, 2));
btPanel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.LIGHT_GRAY),
BorderFactory.createEmptyBorder(4, 4, 4, 4)
));
btPanel.add(ok);
btPanel.add(exit);
หลงั จากนน้ั เราก็สราง JPanel สําหรับเกบ็ panel ทง้ั สามตวั
leftPanel = new JPanel(new BorderLayout());
leftPanel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.LIGHT_GRAY),
BorderFactory.createEmptyBorder(2, 2, 2, 2)
));
leftPanel.add(cbPanel, BorderLayout.WEST);
leftPanel.add(tfPanel, BorderLayout.EAST);
leftPanel.add(btPanel, BorderLayout.SOUTH);
ขั้นตอนตอ ไปก็สรา ง JTextArea ดว ยขนาด 7 x 20 พรอ มทง้ั กาํ หนดใหม ีขอ ความเบอื้ งตน ท่ีมี
การ highlight อยูภายใน และยงั ไดกําหนดใหก ารใสขอ ความภายในมกี ารตดั คาํ ไปยงั บรรทดั
ใหมด ว ย
area = new JTextArea(7, 20);
area.setText("Enter your sentences here.");
area.selectAll();
area.setLineWrap(true);
area.setWrapStyleWord(true);
เน่อื งจากวา ผใู ชอาจใสขอ ความทม่ี ีความยาวเกินขอบเขตของ JTextArea ดังนัน้ เราจึงกําหนดให
JTextArea น้ีอยูใน scroll pane เพื่อใหส ามารถเล่อื นข้ึนลงเพอิ่ ดูขอความได
JScrollPane scrollPane = new JScrollPane(area);
เสรจ็ แลวกน็ ํา component ท้งั สองเขาสู panel หลกั ตอไป
add(leftPanel);
add(scrollPane);
โปรแกรมตวั อยา งเมื่อ run ในคร้งั แรกนั้น component ท่ีมี focus (component ที่กําลงั active)
น้ันคอื JCheckBox ตัวแรกที่ชอ่ื words แตเราตองการใหโปรแกรมของเรานนั้ มี focus ที่
ขอ ความทีเ่ ราได highlight ไวใน JTextArea เพ่อื ใหผ ใู ชส ามารถเขียนขอความใหมท ับไดท นั ที
เราจึงตอ งเขยี น code ไวใน constructor ของ class WordsFrame ดงั น้ี
addWindowListener(new WindowAdapter() {
public void windowActivated(WindowEvent e) {
panel.area.requestFocusInWindow();
}
});
โดยที่ panel เปน JPanel หลกั ทใ่ี ชเ กบ็ component ตาง ๆ และ area เปน JTextArea ที่เราให
ความสนใจ เราจงึ เรียกใช method requestFocusInWindow() บน area ทอ่ี ยูใ น panel น้ี
364
บทที่ 11: GUI และ Event Handling intro. to Java (FEU.faa)
เม่อื จดั วาง UI เสรจ็ แลว เรากต็ อ งเขยี น code สาํ หรบั การดักฟง event ที่จะเกิดข้ึนจากผใู ช เรา
จะแสดงผลก็ตอ เม่ือผใู ชกดปมุ OK เทา น้ัน
public void actionPerformed(ActionEvent e) {
String list = area.getText();
int[] counts = new int[3];
counts = getAllCounts(list);
if(e.getSource() == ok) {
if(words.isSelected())
wdCount.setText("" + counts[0]);
else
wdCount.setText("");
if(vowels.isSelected())
vwCount.setText("" + counts[1]);
else
vwCount.setText("");
if(spaces.isSelected())
spCount.setText("" + counts[2]);
else
spCount.setText("");
}
if(e.getSource() == exit) {
System.exit(0);
}
}
เราดงึ ขอความออกจาก JTextArea ดวยการเรียกใช method getText() ไปเกบ็ ไวใ นตัวแปร list
เราจะสง list ไปให method getAllCount() ประมวลผล เกบ็ ผลลพั ธท ี่ไดไ วใ น array counts
โดยกาํ หนดให count[0] เกบ็ จํานวนของคํา count[1] เก็บจาํ นวนของสระ และ count[2] เก็บ
จาํ นวนของชองวาง หลงั จากนนั้ เรากต็ รวจสอบวา ระหวา งปมุ OK กับปมุ EXIT ตัวไหนถกู กด ถา
เปน ปมุ OK เราก็จะตรวจสอบตอ ไปวา check box ตัวไหนระหวาง words, vowels และ spaces
ถูกเลอื ก หรอื ถกู เลือกท้งั หมด การแสดงผลกข็ น้ึ อยกู ับ check box เหลาน้ี เราจะไมแ สดง code
ท่อี ยภู ายใน method getAllCount() ผอู า นดไู ดจ าก code ท้ังหมดของโปรแกรมเอง ภาพทเี่ หน็
เปนตัวอยางการ run โปรแกรมดวยขอ ความทีใ่ สเ ขามาจาก keyboard
ภาพท่ี 11.9 ตัวอยางการ run โปรแกรม CountWords.java
ผูอ า นไมจ ําเปนตอ งใสขอความในโปรแกรมตวั นี้ เพือ่ เรยี กใช JCheckBox เพราะเรามขี อ ความ
เบ้อื งตนอยภู ายใน JTextArea เพ่ือดัก error ทอ่ี าจเกิดข้นึ ถา ผใู ชเ ลอื ก check box ใด check
box หนง่ึ แลวกดปมุ OK
[การแสดงผลลพั ธท นั ทที ่ีผูใชเลอื ก check box]
เราไมจ ําเปน ทตี่ องใชป มุ OK เปน ตัวกาํ หนดการประมวลผลในโปรแกรม CountWords.java กไ็ ด
เราอาจใหม ีการประมวลผลทันทีทผ่ี ูใ ชเ ลอื ก check box ตัวใดตัวหนงึ่ ซึ่งในการกระทาํ ดังกลา ว
เราตอ งเปลยี่ น code ภายใน method actionPerformed() ใหทาํ การตรวจสอบการเลอื กของ
check box ทนั ทโี ดยไมต องตรวจสอบการกดปุม วิธีการกง็ ายมาก เพียงแคเ อา code ท่วี า
365
เร่มิ ตน การเขยี นโปรแกรมดว ย Java
if(e.getSource() == ok) {
และเครอื่ งหมายปก กา } ทป่ี ดตัว if ออกดว ยกเ็ ทานนั้ เอง (แตย งั เก็บ code ทอี่ ยูภ ายในไว)
Code ท้งั หมดของ CountWords.java มีดังนี้
1: /** intro. to Java (FEU.faa)
2: Using JCheckBox, JTextField, JTextArea and BorderFactory
3: */
4:
5: import javax.swing.*;
6: import javax.swing.border.*;
7: import java.awt.*;
8: import java.awt.event.*;
9: import java.util.*;
10: import java.text.*;
11:
12: class CountWords {
13: public static void main(String[] args) {
14: JFrame.setDefaultLookAndFeelDecorated(true);
15: JFrame frame = new WordsFrame();
16: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
17: frame.setVisible(true);
18: }
19: }
20:
21: class WordsFrame extends JFrame {
22: WordsPanel panel;
23:
24: //create a frame and a panel
25: public WordsFrame() {
26: setTitle("Words, vows and spaces");
27: panel = new WordsPanel();
28:
29: /**
30: The first component in the frame that has focus is
31: JCheckBox: words. We need to move the focus to JTextArea,
32: so we make sure 'area' in JPanel gets the focus
33: whenever a frame is activated.
34: This is a work-around solution, a simple call to
35: requestFocusInWindow() on text area should work, but it didn't!
36: */
37: addWindowListener(new WindowAdapter() {
38: public void windowActivated(WindowEvent e) {
39: panel.area.requestFocusInWindow();
40: }
41: });
42:
43: //add this panel to the frame
44: add(panel);
45: pack();
46: }
47: }
48:
49: //words, vows and spaces panel
50: class WordsPanel extends JPanel implements ActionListener {
51: JPanel cbPanel; //panel for check boxes
52: JPanel tfPanel; //panel for text fields
53: JPanel btPanel; //panel for buttons
54: JPanel leftPanel; //panel for panels above
55: JCheckBox words; //word count check box
56: JCheckBox vowels; //vowel count check box
57: JCheckBox spaces; //space count check box
58: JButton ok; //ok button
59: JButton exit; //exit button
60: JTextArea area; //area for input
61: JTextField wdCount; //text field for words
62: JTextField vwCount; //text field for vowels
63: JTextField spCount; //text field for spaces
64: Font font = new Font("Serif", Font.BOLD, 12);
65:
366
บทท่ี 11: GUI และ Event Handling
66: public WordsPanel() { intro. to Java (FEU.faa)
setLayout(new FlowLayout());
67:
68: //JCheckBox in a panel
69: words = new JCheckBox("Words");
words.addActionListener(this);
70: vowels = new JCheckBox("Vowels");
71: vowels.addActionListener(this);
spaces = new JCheckBox("Spaces");
72: spaces.addActionListener(this);
73: cbPanel = new JPanel(new GridLayout(3, 1));
74: cbPanel.add(words);
75: cbPanel.add(vowels);
76: cbPanel.add(spaces);
77:
78: //JTextFields in a panel
79: wdCount = new JTextField(8);
80: wdCount.setEditable(false);
81: wdCount.setFont(font);
82: wdCount.setHorizontalAlignment(JTextField.CENTER);
83: vwCount = new JTextField(8);
84: vwCount.setEditable(false);
85: vwCount.setFont(font);
86: vwCount.setHorizontalAlignment(JTextField.CENTER);
87: spCount = new JTextField(8);
88: spCount.setEditable(false);
89: spCount.setFont(font);
90: spCount.setHorizontalAlignment(JTextField.CENTER);
91: tfPanel = new JPanel(new GridLayout(3, 1, 2, 2));
92: tfPanel.add(wdCount);
93: tfPanel.add(vwCount);
94: tfPanel.add(spCount);
95:
96: //ok and exit buttons in their panel
97: ok = new JButton("OK");
98: ok.addActionListener(this);
99: exit = new JButton("EXIT");
exit.addActionListener(this);
100: btPanel = new JPanel(new GridLayout(1, 2, 2, 2));
101: btPanel.setBorder(BorderFactory.createCompoundBorder(
102: BorderFactory.createLineBorder(Color.LIGHT_GRAY),
BorderFactory.createEmptyBorder(4, 4, 4, 4)
103: ));
104: btPanel.add(ok);
btPanel.add(exit);
105:
//panel contains JCheckBox panel,
106: //JTextField panel and JButton panel
107: leftPanel = new JPanel(new BorderLayout());
leftPanel.setBorder(BorderFactory.createCompoundBorder(
108:
BorderFactory.createLineBorder(Color.LIGHT_GRAY),
109: BorderFactory.createEmptyBorder(2, 2, 2, 2)
110: ));
leftPanel.add(cbPanel, BorderLayout.WEST);
111: leftPanel.add(tfPanel, BorderLayout.EAST);
112: leftPanel.add(btPanel, BorderLayout.SOUTH);
113: //area where input is entered
area = new JTextArea(7, 20);
114: area.setText("Enter your sentences here.");
115: /**
116: highlights the default text and
wraps each word in the area.
117: */
118: area.selectAll();
area.setLineWrap(true);
119: area.setWrapStyleWord(true);
120: //add area to scroll pane to get auto-activate scroll bar
121: JScrollPane scrollPane = new JScrollPane(area);
122:
123: //add components to the main panel
124: add(leftPanel);
125: add(scrollPane);
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
367
เริม่ ตน การเขียนโปรแกรมดวย Java
140: } intro. to Java (FEU.faa)
141: //performs action
142: public void actionPerformed(ActionEvent e) {
143:
//gets sentences from JTextArea
144: String list = area.getText();
145: //array to store each count
int[] counts = new int[3];
146: //calls getAllCounts() to process the list.
147: counts = getAllCounts(list);
148:
149: //OK button is clicked
150: if(e.getSource() == ok) {
151:
152: //words check box
153: if(words.isSelected())
154:
155: wdCount.setText("" + counts[0]);
156: else
157:
158: wdCount.setText("");
159:
160: //vows check box
161: if(vowels.isSelected())
162:
163: vwCount.setText("" + counts[1]);
164: else
165:
166: vwCount.setText("");
167:
168: //spaces check box
169: if(spaces.isSelected())
170:
171: spCount.setText("" + counts[2]);
172: else
173:
spCount.setText("");
174: }
175:
//EXIT button is clicked
176: if(e.getSource() == exit) {
177: System.exit(0);
178: }
}
179:
//counts words, vowels and spaces
180: private int[] getAllCounts(String list) {
181:
/**
182: counted[0] = words,
counted[1] = vowels,
183: counted[2] = spaces.
184:
*/
185: int[] counted = new int[3];
186:
boolean preWhite = true; //white space ahead of a word
187: int index = 0;
188: //loops through each character in the string
189: while(index < list.length()) {
190: char ch = list.charAt(index++);
boolean curWhite = Character.isWhitespace(ch);
191: /**
192:
only when we found a white space after
193: each word, this statement is true.
*/
194: if(preWhite && !curWhite)
195:
196: counted[0]++;
197: preWhite = curWhite;
198:
199: if(curWhite)
200: counted[2]++;
201:
202: ch = Character.toLowerCase(ch);
203: if(ch == 'a' || ch == 'e' || ch == 'i' ||
204:
205: ch == 'o' || ch == 'u')
206: counted[1]++;
207:
208: }
209: return counted;
210: }
211:
212: }
368
บทท่ี 11: GUI และ Event Handling intro. to Java (FEU.faa)
ถาเราตองการใหม ีการ confirm หลังจากทผี่ ใู ชก ดปมุ EXIT เชนเดยี วกันกบั ที่โปรแกรมหลาย ๆ
ตัวนยิ มทํากัน เรากท็ าํ ไดด วยการเปล่ยี น code ทีต่ รวจสอบปมุ EXIT ใหท าํ การแสดง dialog
window ดังนี้
if(e.getSource() == exit) {
int status = JOptionPane.showConfirmDialog(null, "Are you sure?");
if(status == JOptionPane.OK_OPTION)
System.exit(0);
}
11.5 JSlider และ JSpinner
JSlider เปนองคป ระกอบอกี ตวั หน่ึงทย่ี อมใหก ารเปล่ยี นแปลงตัวเลือกอยใู นแบบตอเนอ่ื ง
โปรแกรมตัวอยา งทเ่ี ราแสดงใหด ูนีเ้ ปน การเปลีย่ นองศาจาก Celsius ใหเปน Fahrenheit หรอื
จาก Fahrenheit ใหเ ปน Celsius โดยการเปลย่ี นแปลงจะเกดิ ข้ึนโดยอตั โนมตั ิถาหาก slider ตวั
ถูกเคล่อื นขนึ้ หรือลง slider อีกตวั ก็จะเคล่ือนตามคา ที่ไดถ กู เปลย่ี นไปจากการคาํ นวณ
ภาพที่ 11.10 การใช JSlider
การสรา ง JSlider ก็ทาํ ไดด วยการประกาศ JSlider fahSlider = new JSlider() เชน
fahSlider = new JSlider(JSlider.VERTICAL);
fahSlider.setMaximum(MAX_FAH);
fahSlider.setMinimum(MIN_FAH);
fahSlider.setMajorTickSpacing(10);
fahSlider.setMinorTickSpacing(5);
fahSlider.setPaintTicks(true);
fahSlider.setPaintLabels(true);
369
เริ่มตน การเขยี นโปรแกรมดวย Java intro. to Java (FEU.faa)
fahSlider.setValue(0);
fahSlider.addChangeListener(this);
การประกาศท่เี ห็นนเี้ รากําหนดให slider ของเราอยูใ นแนวตัง้ (vertical) ดวยการกําหนดคา
ภายใน constructor ใหเปน JSlider.VERTICAL (ผูอ านสามารถเปลยี่ นใหเปน แนวนอนดว ยการ
ใช JSlider.HORIZONTAL แทน) พรอ มกับกําหนดใหคาสงู สดุ และคา ตา่ํ สดุ มคี า เปน MAX_FAH
และ MIN_FAH ตามลาํ ดบั เรายังสามารถกาํ หนดใหม ีขดี บอกคา ใน slider ดว ยการเรยี กใช
method setPaintTicks(true) และ setPaintLabels(true) พรอ มท้งั กาํ หนดใหมีขดี บอกคา ดวย
method setMeajorTickSpacing(10) และ method setMinorSpacing(5) ซึง่ หมายถงึ การ
กาํ หนดขดี หลักใหห า งกนั 10 หนว ยและขดี รองหา งกัน 5 หนวย (หนวยของ slider) เรายังได
กาํ หนดคา เริม่ ตน ของ slider ใหช ท้ี ี่ 0
การดักฟง event ของ JSlider นั้นเราใช interface ChangeListener เพราะฉะนน้ั เราจงึ ตอ งเรยี ก
method addChangeListener() บน JSlider น้ัน และ method ที่เราตองสรา งขึน้ สาํ หรับการ
สนองตอบกค็ อื method stateChanged() ดงั นี้
public void stateChanged(ChangeEvent e) {
int temp;
JSlider s = (JSlider)e.getSource();
if(s == fahSlider) {
temp = fahSlider.getValue();
celSlider.setValue((int)((temp - 32) / 1.8));
}
else {
temp = celSlider.getValue();
fahSlider.setValue((int)((temp * 1.8) + 32));
}
}
สว น code อื่น ๆ ของโปรแกรมการใช JSlider ก็มีดงั น้ี
1: /**
2: Using JSlider and ChangeListener
3: */
4:
5: import javax.swing.*;
6: import javax.swing.border.*;
7: import javax.swing.event.*;
8: import java.awt.*;
9: import java.awt.event.*;
10:
11: class TempConversion {
12: public static void main(String[] args) {
13: JFrame.setDefaultLookAndFeelDecorated(true);
14: JFrame frame = new SliderFrame();
15: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
16: frame.setVisible(true);
17: }
18: }
19:
20: class SliderFrame extends JFrame implements ChangeListener {
21: JLabel celTitle; //Celcius tttle
22: JLabel fahTitle; //Fahrenheit title
23: JSlider celSlider;//Celsius's slider
24: JSlider fahSlider;//Fahenheit's slider
25: JPanel titlePanel;//panel for titles
26: JPanel tempPanel; //panel for sliders
27: private final int WIDTH = 300, HEIGHT = 480;
28: private final int MIN_FAH = -40, MAX_FAH = 120;
29:
30: public SliderFrame() {
31: setTitle("Temperature Conversion");
32: setSize(WIDTH, HEIGHT);
33: setLayout(new BorderLayout());
34:
35: //creates titles and panel
36: celTitle = new JLabel("Celsius");
37: celTitle.setHorizontalAlignment(JLabel.CENTER);
370
บทท่ี 11: GUI และ Event Handling
38: fahTitle = new JLabel("Fahrenheit"); intro. to Java (FEU.faa)
fahTitle.setHorizontalAlignment(JLabel.CENTER);
39:
40: titlePanel = new JPanel(new GridLayout(1, 2));
titlePanel.add(celTitle);
41: titlePanel.add(fahTitle);
42: //creates slider for Celsius with values corresponding
43: //to max and min Fahrenheit
celSlider = new JSlider(JSlider.VERTICAL);
44: celSlider.setMaximum((int)((MAX_FAH - 32) / 1.8));
45: celSlider.setMinimum((int)((MIN_FAH - 32) / 1.8));
celSlider.setMajorTickSpacing(5);
46: celSlider.setMinorTickSpacing(1);
celSlider.setPaintTicks(true);
47: celSlider.setPaintLabels(true);
48: celSlider.setValue((int)((0 - 32) / 1.8));
celSlider.addChangeListener(this);
49:
//creates slider for Fahrenheit with default values
50: fahSlider = new JSlider(JSlider.VERTICAL);
51: fahSlider.setMaximum(MAX_FAH);
fahSlider.setMinimum(MIN_FAH);
52: fahSlider.setMajorTickSpacing(10);
fahSlider.setMinorTickSpacing(5);
53: fahSlider.setPaintTicks(true);
54: fahSlider.setPaintLabels(true);
fahSlider.setValue(0);
55: fahSlider.addChangeListener(this);
56: //adds sliders to panel
57: tempPanel = new JPanel(new GridLayout(1, 2));
tempPanel.add(celSlider);
58: tempPanel.add(fahSlider);
59:
//adds panels to frame
60: add(titlePanel, BorderLayout.NORTH);
add(tempPanel, BorderLayout.CENTER);
61: }
62:
//monitor state changes from slider
63: public void stateChanged(ChangeEvent e) {
64: int temp;
65: JSlider s = (JSlider)e.getSource();
66: //converts to Fahrenheit if Celsius slider is activated
if(s == fahSlider) {
67:
68: temp = fahSlider.getValue();
celSlider.setValue((int)((temp - 32) / 1.8));
69: }
//converts to Celsius if Fahrenheit slider is activated
70: else {
71: temp = celSlider.getValue();
fahSlider.setValue((int)((temp * 1.8) + 32));
72: }
73: }
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94: }
[การใช JSpinner]
โปรแกรมตวั อยา งตอไปทีจ่ ะแสดงใหดเู ปนการใช JSpinner ในการเปลย่ี นอณุ หภมู ิเชนทไ่ี ดทํา
ในโปรแกรม TempConversion.java
JSpinner เปน text field ชนิดหน่ึงท่ีมปี มุ เล็ก ๆ สองปมุ อยดู า นขาง ซง่ึ เมือ่ ปมุ ถกู กดคาใน text
field กจ็ ะเปลี่ยนแปลงในลักษณะของการเพิ่มหรือการลดคา คา ทอี่ ยใู น spinner สามารถเปน ได
ทั้งตวั เลข วนั /เวลา คาทอ่ี ยใู น list หรอื คาใด ๆ ที่สามารถหาคากอนหนาหรอื คา ทต่ี ามมาได
เราจะดดั แปลงโปรแกรมเลก็ นอ ยเพื่อเปนการใหผ อู านไดสมั ผัสถงึ การใช JSpinner อยา งงา ย ๆ
โดยเราจะกําหนดใหม ี spinner 1 ตวั สําหรับการกาํ หนดคาและจะใช label 2 ตวั เปน ตวั แสดงคา
ของอุณหภมู ทิ เ่ี ปน Celsius และ Fahrenheit จากคา ท่ีไดจ าก spinner นี้
371
เร่มิ ตนการเขยี นโปรแกรมดว ย Java intro. to Java (FEU.faa)
JSpinner
ภาพท่ี 11.11 การใช JSpinner
ภาพตัวอยา งผลลัพธที่ไดแสดงใหเ ห็นถงึ การใช JSpinner ทมี่ ีคา เทากบั 32 พรอ มกับแสดงคา
ของ Celsius และ Fahrenheit (32°F = 0°C และ 32°C = 89°F)
การประกาศใช JSpinner กท็ ําไดส องแบบคอื
JSpinner spinner = new JSpinner();
หรือ
JSpinner spinner;
spinner = new JSpinner(new SpinnerNumberModel(START, MIN, MAX, 1));
โดยท่ีการประกาศตัวแรกเปน การใช spinner ทม่ี คี า เปน integer เรมิ่ ตน ที่ 0 และมคี าเพ่มิ หรอื ลด
ทลี ะหน่ึงคา สวนตัวทสี่ องเปนการเรยี กใช spinner model ทม่ี อี ยูด วยคา เรม่ิ ตนที่ START คา
ตํา่ สดุ คือ MIN คา สูงสุดคอื MAX และการเพ่ิมหรอื ลดคาเปน ทลี ะหน่ึงคา
การดงึ คา ออกจาก spinner ก็เรียกใช method getValue() เชน
value = (Integer)spinner.getValue();
ทงั้ นเ้ี ราตองเปลีย่ นคา ทส่ี งกลบั ใหเปน ไปตามคาที่เราตอ งการใช เนื่องจากวา getValue() จะสง
Object กลบั ออกมา
สาํ หรบั model ตัวอ่นื ๆ ท่ี Java มใี หกค็ อื SpinnerListModel และ SpinnerDateModel แตเ ราก็
สามารถสรา ง model ขนึ้ มาใชเ องได
Code ท้ังหมดของโปรแกรม TempConversion2.java มีดงั น้ี
1: /**
2: Using JSpinner
3: */
4:
5: import javax.swing.*;
6: import javax.swing.border.*;
7: import javax.swing.event.*;
8: import java.awt.*;
9: import java.awt.event.*;
10:
11: class TempConversion2 {
12: public static void main(String[] args) {
13: JFrame.setDefaultLookAndFeelDecorated(true);
14: JFrame frame = new SpinnerFrame();
15: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
16: frame.setVisible(true);
17: }
18: }
19:
372
บทท่ี 11: GUI และ Event Handling intro. to Java (FEU.faa)
20: class SpinnerFrame extends JFrame implements ChangeListener {
21: JSpinner spinner;
22: JPanel panel, panel1, panel2;
23: JLabel celTitle, fahTitle;
24: JLabel window1,window2;
25: private final int WIDTH = 250, HEIGHT = 90;
26: private final int MIN = -200, MAX = 200;
27: private final int START = 0;
28:
29: public SpinnerFrame() {
30: setTitle("Temperature");
31: setSize(WIDTH, HEIGHT);
32:
33: //cteate JSpinner with initial values
34: spinner = new JSpinner(new SpinnerNumberModel(START, MIN, MAX, 1));
35: spinner.setBorder(BorderFactory.createCompoundBorder(
36: BorderFactory.createLineBorder(Color.LIGHT_GRAY),
37: BorderFactory.createEmptyBorder(2, 2, 2, 2)
38: ));
39: spinner.addChangeListener(this);
40:
41: celTitle = new JLabel("Celsius");
42: celTitle.setHorizontalAlignment(JLabel.CENTER);
43: fahTitle = new JLabel("Fahrenheit");
44: fahTitle.setHorizontalAlignment(JLabel.CENTER);
45:
46: panel1 = new JPanel(new GridLayout(1, 3, 2, 2));
47: panel1.setBorder(BorderFactory.createCompoundBorder(
48: BorderFactory.createLineBorder(Color.LIGHT_GRAY),
49: BorderFactory.createEmptyBorder(4, 4, 4, 4)
50: ));
51: panel1.add(celTitle);
52: panel1.add(new JLabel("F / C", JLabel.CENTER));
53: panel1.add(fahTitle);
54:
55: window1 = new JLabel(" ", JLabel.CENTER);
56: window2 = new JLabel(" ", JLabel.CENTER);
57:
58: panel2 = new JPanel(new GridLayout(1, 3, 2, 2));
59: panel2.setBorder(
60: BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
61: panel2.add(window1);
62: panel2.add(spinner);
63: panel2.add(window2);
64:
65: panel = new JPanel(new BorderLayout());
66: panel.add(panel1, BorderLayout.NORTH);
67: panel.add(panel2, BorderLayout.CENTER);
68:
69: add(panel, BorderLayout.CENTER);
70: }
71:
72: //performs event
73: public void stateChanged(ChangeEvent e) {
74: int value;
75: String cel, fah;
76:
77: //gets value fromspinner
78: value = (Integer)spinner.getValue();
79:
80: //converts it to Celsius and sends it to window
81: cel = "" + (int)((value - 32) / 1.8);
82: window1.setText(cel);
83:
84: //converts to Fahrenheit and sends it to window
85: fah = "" + (int)((value * 1.8) + 32);
86: window2.setText(fah);
87: }
88: }
373
เริม่ ตน การเขียนโปรแกรมดว ย Java
11.6 JProgressBar และ ProgressMonitor
ในกรณีท่ีเราตองการแสดงถงึ ขน้ั ตอนความกาวหนา ของการทาํ งานในโปรแกรม เชน การ
download ขอ มลู จาก WWW หรือการอานขอ มูลจากหนวยความจาํ หนึง่ ใน component ที่เรา
สามารถเรยี กใชไ ดค อื JProgressBar ภาพท่ี 11.12 แสดงการใช JProgressBar กบั งานสมมตทิ ่ี
เราสรา งขนึ้ ดว ยการใช Thread
JButton JTextField แสดงจํานวนของ intro. to Java (FEU.faa)
งานท่ีเกิดขน้ึ
JProgressBar ทม่ี ีการ Cursor ขณะท่งี าน
แสดง % ของงาน กาํ ลังกาวหนา
ภาพท่ี 11.12 การใช JProgressBar
JProgressBar เปน component ทีเ่ ปน รปู สี่เหลี่ยมท่ีมกี าร fill ดว ยสเี พื่อเปน การบอกถงึ
ความกา วหนา ของงานหรอื กระบวนการ เชน ในภาพความคืบหนาของงานถกู บอกดวย n% เรา
สราง progress bar ดว ย
progressBar = new JProgressBar();
ถาเราตองการใหม กี ารแสดงความคืบหนา เราใช
progressBar.setStringPainted(true);
เราสามารกําหนดคาสูงสดุ ที่ progress bar แสดงดวย
progressBar.setMaximum(1000);
ในขณะทีง่ านกาํ ลังดาํ เนนิ อยหู ากเราตองการใหแ สดงสถานะของ cursor เพื่อบอกใหผ ูใชรวู า
งานกําลังถกู execute เรากใ็ ช
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
และเมอื่ เสรจ็ งานเรากเ็ ปล่ยี น cursor กลับเปนอยา งเดิมดวย
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
cursor ยังมรี ูปแบบอีกหลายแบบทเ่ี ราสามารถใชไ ด ซึ่งผูอานสามารถหาดูไดจ าก Java API เอง
โปรแกรมตวั อยา งของเราใช Thread simulation เปน ตวั สรา งงานอยา งงาย ๆ น่ันก็คือ เพม่ิ คา
ใหก ับตวั แปรทลี ะหนึ่งคา ทกุ ๆ ครัง้ หลังจากถกู interrupt ใหก ลบั มาทํางานหลงั จากการ sleep
ไประยะเวลาหนง่ึ ในเวลาเดยี วกนั thread ก็เรยี ก method setValue() ของ JProgressBar เพอ่ื
ทาํ การเปลยี่ นคา ของ progress bar กระบวนการจะสิ้นสดุ ลงเมอื่ คาที่เปลย่ี นแปลงเทากบั คา ของ
target ทไี่ ดกําหนดไว
เนอื่ งจากวาการเรียก Swing method จะตองทําใน event dispatching thread ดังน้นั เราจงึ
ปรบั ปรุง code ใหร องรับงานดงั กลา ว (ผูอา นจะเห็นวา code สว นน้ีจะแตกตา งจากสว นอนื่ ซ่ึงใน
บางครั้งตวั อยางทีไ่ มซ บั ซอ นมากนกั กจ็ ะไมสนใจเร่อื งของ thread safe นี้ เพราะเราเพียงแต
ตองการแสดงใหด ูเปนตัวอยา งเทา น้ัน) อีกสง่ิ หนง่ึ ท่เี ราทํากบั โปรแกรมตวั อยางนี้คือ การ
374
บทท่ี 11: GUI และ Event Handling intro. to Java (FEU.faa)
กาํ หนดการสนองตอบตอ event นน้ั จะทาํ บน component นน้ั ๆ ทันที กลา วคอื เราจะเขียน
code ลงบน component แตจ ะไมสรา ง method actionPerformed() หลักของตัวโปรแกรมเอง
เพอื่ งานดังกลาว เชน การสนองตอบตอการทาํ งานของปุม Start และงานของ Timer
start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
progressBar.setMaximum(1000);
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
activity = new Activity(1000);
new Thread(activity).start();
timer.start();
start.setEnabled(false);
}
});
timer = new Timer(500, new ActionListener() {
public void actionPerformed(ActionEvent e) {
int current = activity.getCurrent();
showText.setText("" + current);
progressBar.setStringPainted(true);
progressBar.setValue(current);
if(current == activity.getTarget()) {
timer.stop();
start.setEnabled(true);
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
});
ปมุ Start จะเปน ตัวกําหนดคาเบอื้ งตนใหกับ progress bar กําหนดหนาตาของ cursor สรา ง
activity สมมติ เร่มิ การทาํ งานของ Thread ดวย activity ทส่ี รา งขนึ้ เรมิ่ การทาํ งานของ Timer
และปลดปุม (disable) Start เพอ่ื ไมใหผ ใู ชก ดอีก
ภายในตวั timer เองกจ็ ะดึงเอาคาของ current ออกมาเพ่ือแสดงผลใน text field ปรบั ปรงุ
progress bar และตรวจสอบดูวา งานทที่ าํ ไดเ ปา หมายหรอื ยัง ถา ถึงแลวกห็ ยุดการทาํ งานของ
timer (timer.stop()) เปลยี่ นปมุ Start ใหอ ยูในสถานะทผ่ี ใู ชก ดได (enable) พรอมกับเปลย่ี น
cursor ใหเ ปน รปู เดิม (default cursor)
Code ทง้ั หมดของโปรแกรมมดี งั นี้
1: /**
2: Using JProgressBar
3: */
4:
5: import java.awt.*;
6: import java.awt.event.*;
7: import javax.swing.*;
8: import javax.swing.Timer;
9: import javax.swing.event.*;
10: import javax.swing.border.*;
11:
12: public class SimulatedTask extends JPanel {
13: private JProgressBar progressBar;
14: private JButton start;
15: private Timer timer;
16: private JTextField showText;
17: private Activity activity;
18:
19: public SimulatedTask() {
20: super(new BorderLayout());
21:
22: showText = new JTextField(10);
23: showText.setHorizontalAlignment(JTextField.CENTER);
24: showText.setFont(new Font("Dialog", Font.BOLD, 12));
25: showText.setEditable(false);
26:
27: start = new JButton("Start");
28:
29: progressBar = new JProgressBar();
375
เริ่มตน การเขียนโปรแกรมดว ย Java
30: progressBar.setBorder(
31: BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
32: progressBar.setStringPainted(true);
33:
34: JPanel panel = new JPanel(new GridLayout(1, 2, 2, 2));
35: panel.add(start);
36: panel.add(showText);
37:
intro. to Java (FEU.faa)
38: add(panel, BorderLayout.NORTH);
39: add(progressBar, BorderLayout.SOUTH);
40:
41: //performs activity when button is hit
42: start.addActionListener(new ActionListener() {
43: public void actionPerformed(ActionEvent e) {
44: progressBar.setMaximum(1000);
45: setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
46: activity = new Activity(1000);
47: new Thread(activity).start();
48: timer.start();
49: start.setEnabled(false);
50: }
51: });
52:
53: //starts timer and shows progress
54: timer = new Timer(500, new ActionListener() {
55: public void actionPerformed(ActionEvent e) {
56: int current = activity.getCurrent();
57: showText.setText("" + current);
58: progressBar.setStringPainted(true);
59: progressBar.setValue(current);
60: if(current == activity.getTarget()) {
61: timer.stop();
62: start.setEnabled(true);
63: setCursor(Cursor.getPredefinedCursor(
Cursor.DEFAULT_CURSOR));
64: }
65: }
66: });
67: }
68:
69: //creates and show GUI
70: private static void setGUI() {
71: JFrame.setDefaultLookAndFeelDecorated(true);
72:
73: //creates and set up the window.
74: JFrame frame = new JFrame("JProgessBar");
75: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
76:
77: //creates and set up the content pane.
78: JComponent newContentPane = new SimulatedTask();
79: newContentPane.setOpaque(true); //content panes must be opaque
80: frame.setContentPane(newContentPane);
81:
82: //displays the window.
83: frame.pack();
84: frame.setVisible(true);
85: }
86:
87: public static void main(String[] args) {
88: //schedules a job for the event-dispatching thread:
89: //creating and showing this application's GUI.
90: javax.swing.SwingUtilities.invokeLater(new Runnable() {
91: public void run() {
92: setGUI();
93: }
94: });
95: }
96: }
97:
98: //simulated activity for progress bar
99: class Activity implements Runnable {
100: private int target;
101: private volatile int current;
102:
376
บทท่ี 11: GUI และ Event Handling
103: public Activity(int t) { intro. to Java (FEU.faa)
current = 0;
104: target = t;
105:
106: }
107: public int getTarget() {
108: return target;
109: }
110:
111: public int getCurrent() {
112: return current;
113:
114: }
115:
116: public void run() {
117: try {
118: while(current < target) {
119: Thread.sleep(10);
120: current++;
121: }
122: }
123: catch(InterruptedException e) {}
124:
125: } }
[ProgressMonitor]
Progress monitor เปน component อีกตัวหนึ่งท่เี ราสามารถใชด คู วามคืบหนาของงานได
เชน เดียวกบั JProgressBar แตตา งจาก progress bar ตรงทวี่ า progress monitor จะใช
dialog box เปนตัวแสดงความคบื หนาแทน ดังทแ่ี สดงในภาพท่ี 11.13
หลงั จากที่กดปุม Start ได
ประมาณ 1 วินาที dialog
window ก็จะ pop up ขน้ึ มา
พรอ มกับแสดงความคบื หนา
ของงาน ในแทงสีเ่ หลี่ยม สวน
การแสดงคา n% นั้นเราตอง
เรยี กใช method setNote()
ภาพที่ 11.13 ProgressMonitor แสดงความคืบหนาของงาน
การเรียกใช ProgressMonitor กค็ ลายกับ JProgressBar จะตางกนั ตรงทคี่ วามคืบหนา ของงาน
จะถกู แสดงผา นทาง dialog window (pop up) ดังนน้ั เราจะไมส รา ง progress monitor ในที่อ่นื
ใด เชน ทีเ่ ราทํากับ JProgressBar แตเราจะสรา ง progress monitor ใน method
actionPerformed() ของปุม Start ทง้ั น้กี เ็ พราะวา เราจะแสดงความคบื หนาหลงั จากทผี่ ใู ชก ด
ปุม Start นั่นเอง
[ในการที่จะให dialog window ของเรามหี นา ตาทเี่ ปนของ Java เชน เดยี วกนั กบั หนาตา งหลกั
ของโปรแกรมนนั้ เราจะตองกาํ หนด look and feel ของ JDialog ดวย
JDialog.setDefaultLookAndFeelDecorated(true);
หลงั จากท่เี รากาํ หนดหนา ตาของตวั โปรแกรมหลัก (ภายใน method setUI())]
377
เรม่ิ ตนการเขียนโปรแกรมดวย Java
start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
activity = new Activity(1000);
thread = new Thread(activity);
thread.start();
progressDialog = new ProgressMonitor(SimulatedTask2.this, intro. to Java (FEU.faa)
"Waiting for activity",
"Progress: ",
0,
activity.getTarget());
progressDialog.setMillisToDecideToPopup(SECOND);
timer.start();
start.setEnabled(false);
}
});
เราประกาศให progressMonitor เปน Object จาก class ProgerssMonitor ดวย parameter 5
ตวั คือ
1. Component Æ component ที่เปน parent (frame หรอื panel) ของ progress
monitor เอง เชน object ทเี่ กิดจาก class SimulatedTask2 ของเรา
2. message Æ ขอความท่ีตองการแสดงใน dialog window ("Waiting for activity")
3. note Æ ขอความท่อี าจมหี รอื ไมม ีใน dialog window ("Progress")
4. min Æ คา ตาํ่ สดุ ของความคบื หนา (0)
5. max Æ คา สงู สดุ ของความคบื หนา (activity.getTarget())
หลังจากทผี่ ใู ชก ดปมุ Start ไดป ระมาณหน่งึ วินาที dialog window ก็จะ pop up ขน้ึ มาแสดง
ความคบื หนา ของงาน (เราใชค ําส่งั setMillisToDecideToPopup())
การ update ตา ง ๆ กท็ ําใน method actionPerformed() ของ timer
timer = new Timer(500, new ActionListener() {
public void actionPerformed(ActionEvent e) {
int current = activity.getCurrent();
showText.setText("" + current);
progressDialog.setProgress(current);
progressDialog.setNote("Progress: " + (current/10) + "%");
if(current == activity.getTarget() || progressDialog.isCanceled()) {
timer.stop();
progressDialog.close();
thread.interrupt();
start.setEnabled(true);
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
});
เราเรียก method setProgress() สาํ หรบั การแสดงความคืบหนา และเรยี ก method setNote()
สาํ หรบั คา % ทแ่ี สดงใน dialog window และเมือ่ งานสนิ้ สดุ ลงเรากเ็ รยี ก method close() ของ
class ProgressMonitor และ method interrupt() ของ class Thread สว น code อื่น ๆ ก็
เหมือนกับทเี่ ราทาํ ในโปรแกรมตวั อยา งการใช JProgressBar
Code ของ SimulatedTask2.java มีดังนี้
1: /**
2: Using ProgressMonitor
3: */
4:
5: import java.awt.*;
6: import java.awt.event.*;
7: import javax.swing.*;
8: import javax.swing.Timer;
378
บทที่ 11: GUI และ Event Handling intro. to Java (FEU.faa)
9: import javax.swing.event.*;
10: import javax.swing.border.*;
11:
12: public class SimulatedTask2 extends JPanel {
13: private ProgressMonitor progressDialog;
14: private JButton start;
15: private Timer timer;
16: private JTextField showText;
17: private Thread thread;
18: private JLabel label;
19: private Activity activity;
20: private final int SECOND = 1000;
21:
22: public SimulatedTask2() {
23: super(new BorderLayout());
24:
25:
26: showText = new JTextField(10);
27: showText.setHorizontalAlignment(JTextField.CENTER);
28: showText.setFont(new Font("Dialog", Font.BOLD, 12));
29: showText.setEditable(false);
30:
31: start = new JButton("Start");
32:
33: label = new JLabel("Simulated Task", JLabel.CENTER);
34: label.setBorder(BorderFactory.createEtchedBorder(
35: EtchedBorder.RAISED));
36:
37: JPanel panel = new JPanel(new GridLayout(1, 2, 2, 2));
38: panel.add(start);
39: panel.add(showText);
40:
41: add(panel, BorderLayout.NORTH);
42: add(label, BorderLayout.SOUTH);
43:
44: //performs activity when button is hit
45: start.addActionListener(new ActionListener() {
46: public void actionPerformed(ActionEvent e) {
47: setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
48: activity = new Activity(1000);
49: thread = new Thread(activity);
50: thread.start();
51:
52: progressDialog = new ProgressMonitor(SimulatedTask2.this,
53: "Waiting for activity",
54: "Progress: ",
55: 0,
56: activity.getTarget());
57:
58: progressDialog.setMillisToDecideToPopup(SECOND);
59:
60: timer.start();
61: start.setEnabled(false);
62: }
63: });
64:
65: //starts timer and shows progress
66: timer = new Timer(500, new ActionListener() {
67: public void actionPerformed(ActionEvent e) {
68: int current = activity.getCurrent();
69: showText.setText("" + current);
70: progressDialog.setProgress(current);
71: progressDialog.setNote("Progress: " + (current/10) + "%");
72:
73: if(current == activity.getTarget() ||
74: progressDialog.isCanceled()) {
75: timer.stop();
76: progressDialog.close();
77: thread.interrupt();
78: start.setEnabled(true);
79: setCursor(Cursor.getPredefinedCursor(
80: Cursor.DEFAULT_CURSOR));
81: }
82: }
379
เรม่ิ ตนการเขยี นโปรแกรมดวย Java
83: });
84: }
85:
86: //creates and show GUI
87: private static void setGUI() {
88: //set frame to java look and feel
89: JFrame.setDefaultLookAndFeelDecorated(true);
90: //set look and feel of ProgressMonitor
intro. to Java (FEU.faa)
91: JDialog.setDefaultLookAndFeelDecorated(true);
92:
93: //creates and set up the window.
94: JFrame frame = new JFrame("ProgressMonitor");
95: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
96:
97: //creates and set up the content pane.
98: JComponent newContentPane = new SimulatedTask2();
99: newContentPane.setOpaque(true);
100: frame.setContentPane(newContentPane);
101:
102: //displays the window.
103: frame.pack();
104: frame.setVisible(true);
105: }
106:
107: public static void main(String[] args) {
108: //schedules a job for the event-dispatching thread:
109: //creating and showing this application's GUI.
110: javax.swing.SwingUtilities.invokeLater(new Runnable() {
111: public void run() {
112: setGUI();
113: }
114: });
115: }
116: }
117:
118: //simulated activity for progress monitor
119: class Activity implements Runnable {
120: private int target;
121: private volatile int current;
122:
123: public Activity(int t) {
124: current = 0;
125: target = t;
126: }
127:
128: public int getTarget() {
129: return target;
130: }
131:
132: public int getCurrent() {
133: return current;
134: }
135:
136: public void run() {
137: try {
138: while(current < target) {
139: Thread.sleep(10);
140: current++;
141: }
142: }
143: catch(InterruptedException e) {}
144: }
145: }
380
บทที่ 11: GUI และ Event Handling intro. to Java (FEU.faa)
11.7 JFileChooser, JMenu, JMenuBar และ JMenuItem
โปรแกรมตัวอยา งทแ่ี สดงใหด ตู อไปนี้ เปน โปรแกรม text editor อยา งงา ยท่มี กี ารเรยี กใช menu
และ file chooser ที่ Java มีใหโดยเราจะออกแบบใหมกี ารเปด ไฟลขึ้นมาใชงานไดจ ริง สามารถ
เปลย่ี นแปลงขอ มูลในไฟล และสรางไฟลใ หมไ ด
JMenuBar
JMenu
JMenuItem
ภาพท่ี 11.14 การสรา ง menu
เรากําหนดใหม ตี วั เลือกใน menu อยูสี่ตวั คือ New, Open, Save และ Exit โดยกําหนดให
Open และ Save มกี ารใช icon แสดงถงึ งานทตี่ ัวเลอื กนท้ี าํ การสรา ง menu น้ีเราใช JMenuBar
เปน ตัวสรา ง สวนหัวของ menu ใช JMenu และตวั เลอื กภายในเราใช JMenuItem เปน
ตัวกาํ หนด
private JMenuBar setMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu file = menuBar.add(new JMenu("File"));
file.add(getNewMenuItem());
file.add(getOpenMenuItem());
file.add(getSaveMenuItem());
file.addSeparator();
file.add(getExitMenuItem());
return menuBar;
}
เราสรา งหัวเรื่องของ menu ดวยการเรยี ก constructor ของ JMenu และใสตัวเลอื กดว ยการ
เรียก method add() ซง่ึ เราจะสง JMenuItem ทเี่ ราไดส รา งไวจ าก method
getNewMenuItem(), getOpenMenuItem(), getSaveMenuITem() และ
getExitMenuItem() เรายังไดก ําหนดใหมีเสนแบงระหวา ง menu 3 ตัวแรกและ menu ตวั
สุดทา ยดวยการเรียก method addSeparator() ลองมาดตู ัวอยา งการสราง JMenuItem: open
private JMenuItem getOpenMenuItem() {
JMenuItem item = new JMenuItem("Open", openIcon);
item.setMnemonic('o');
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int value = fc.showOpenDialog(FileChooser.this);
if(value == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
String name = file.getPath();
try {
FileReader reader = new FileReader(file);
area.read(reader, "");
frame.setTitle(title + " " + name);
}
381
เรม่ิ ตน การเขยี นโปรแกรมดว ย Java intro. to Java (FEU.faa)
catch(IOException ioex) {}
}
}
});
return item;
}
เราสรา งตัวเลือกที่มี icon จากประโยค
JMenuItem item = new JMenuItem("Open", openIcon);
ในการสนองตอบตอเหตุการณท ีผ่ ใู ชก ําหนดเราก็เรียกใช method actionPerformed() เชนเดิม
และกาํ หนดใหม กี ารแสดง dialog window สาํ หรับการเลือกไฟลดวย
int value = fc.showOpenDialog(FileChooser.this);
โดยท่ี fc เปน ตัวแปรทีส่ รางมาจาก JFileChooser และ method showOpenDialog() จะแสดง
หนาตางทเี่ ราสามารถเลอื กไฟลไ ด โดยเรากาํ หนดใหไ ฟลท ีถ่ กู เปด เปน ไดท งั้ directory และ file
fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
ภาพท่ี 11.15 Dialog window สาํ หรับการเลอื กไฟล
เม่ือเราเลอื กไฟลใ ดไฟลหน่ึง (ไฟลทเ่ี ก็บขอมลู เปนตวั อักษรเทานนั้ – text file) จาก dialog
window เรากจ็ ะดงึ เอาช่อื และทอี่ ยูของไฟลน อี้ อกมาดว ย เพ่อื นาํ ไปแสดงในสวนหัวของ
หนา ตาง (frame title)
File file = fc.getSelectedFile();
String name = file.getPath();
การอานไฟลก ใ็ ช constructor ของ class FileReader ดว ย parameter: file ท่ีเราไดเ ลือกไว
แลว ซึง่ เรากจ็ ะสง ไฟลต วั นีไ้ ปเปด ใน text area อกี คร้ังหนง่ึ
FileReader reader = new FileReader(file);
area.read(reader, "");
frame.setTitle(title + " " + name);
382
บทท่ี 11: GUI และ Event Handling intro. to Java (FEU.faa)
ภาพท่ี 11.16 Simple Text Editor
Text editor ทเ่ี ราสรา งขึ้นมขี ดี จาํ กดั ในการทาํ งานมากพอสมควร เราไมไดเนนถงึ การสรา ง text
editor แตเ ราตอ งการใหผ อู า นสามารถใช file chooser และสรา ง menu ตาง ๆ ได ถาผอู า น
อยากทีจ่ ะเพิ่มสว นอื่น ๆ เขา สโู ปรแกรมตัวอยา งน้ีก็ยอมทาํ ได แตถ า จะใหเ ปน text editor ทดี่ ี
นัน้ คงตอ งใช component ตวั อื่นแทน text area เชน JTextPane หรือ JEditorPane
ผอู า นสามารถที่จะนาํ เอา image icon ไปแปะไวใน menu bar ไดเชน เดยี วกับท่ีทาํ กบั JMenu:
File ดวยการเพิ่ม component ดังกลาวเขา สู menu bar ภายใน method SetMenuBar() ดงั น้ี
JMenuItem open = new JMenuItem(createImageIcon("open.gif"));
open.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
…
area.setTabSize(2);
…
}
});
menuBar.add(open);
เราเพยี งแตส รา ง menu item บน menu bar ใหเปน icon แลว ก็เพม่ิ code สาํ หรับการ
สนองตอบของผูใ ช (เมอื่ ปุมถกู กด) เชนเดียวกนั กับทเ่ี ราไดท าํ การสนองตอบของ Open ท่มี ีอยู
ใน menu พรอ มกันนเี้ รายงั ไดก าํ หนดใหข นาดของ tab ใน text area ของเรามคี าเทากับ 2
ตวั อกั ษรดว ยคาํ สั่ง area.setTab(2)
ภาพที่ 11.17 image icon สาํ หรบั การเปด ไฟลท่ีเราไดเพมิ่ เขาสูโปรแกรม
ลูกเลน อน่ื ๆ ท่ีผใู ชส ามารถทาํ ได (เพือ่ ให text editor ตัวนด้ี ูดขี ้นึ ) ก็ยังมีอกี มาก เชน การ
กําหนดให text area มเี สน กรอบ การกาํ หนด font เปนตน
383
เรม่ิ ตน การเขียนโปรแกรมดว ย Java intro. to Java (FEU.faa)
Code ทัง้ หมดของโปรแกรม FileChooser.java มีดังนี้
1: /**
2: Using JFileChooser, JMenu, JMenuBar, JMenuItem
3: files used:
4: open.gif
5: save.gif
6: */
7:
8: import java.io.*;
9: import java.awt.*;
10: import java.awt.event.*;
11: import javax.swing.*;
12: import javax.swing.event.*;
13: import javax.swing.border.*;
14: import javax.swing.filechooser.*;
15:
16: public class FileChooser extends JPanel {
17: private static JTextArea area;
18: private static JFileChooser fc;
19: private static JScrollPane scrollPane;
20: private static JFrame frame;
21: private final String newline = "\n";
22: private static final String title = "Simple Text Editor";
23:
24: public FileChooser() {
25: //nothing to do here
26: }
27:
28: //creates content pane
29: public Container createContentPane() {
30: JPanel contentPane = new JPanel(new BorderLayout());
31: contentPane.setOpaque(true);
32:
33: //creates file chooser
34: fc = new JFileChooser();
35: fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
36:
37: //creates text area
38: area = new JTextArea(15, 50);
39: area.setFont(new Font("Tahoma", Font.PLAIN, 12));
40: area.setBorder(BorderFactory.createEtchedBorder(
EtchedBorder.RAISED));
41: scrollPane = new JScrollPane(area);
42:
43: //add area with scroll bar to content pane
44: contentPane.add(scrollPane, BorderLayout.CENTER);
45:
46: return contentPane;
47: }
48:
49: //creates and show GUI
50: private static void setGUI() {
51: //set frame to java look and feel
52: JFrame.setDefaultLookAndFeelDecorated(true);
53: //set look and feel for dialog window
54: JDialog.setDefaultLookAndFeelDecorated(true);
55:
56: //creates and set up the window.
57: frame = new JFrame(title);
58: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
59:
60: //creates and set up the content pane.
61: FileChooser editor = new FileChooser();
62: frame.setJMenuBar(editor.setMenuBar());
63: frame.setContentPane(editor.createContentPane());
64:
65: //displays the window.
66: frame.pack();
67: frame.setVisible(true);
68: }
69:
384
บทที่ 11: GUI และ Event Handling
70: //creates icon intro. to Java (FEU.faa)
protected static ImageIcon createImageIcon(String path) {
71:
72: java.net.URL url = FileChooser.class.getResource(path);
73: if(url != null)
74: return new ImageIcon(url);
75: else
76: return null;
77: }
78:
79: //creates menu
80: private JMenuBar setMenuBar() {
81:
82: JMenuBar menuBar = new JMenuBar();
83: JMenu file = menuBar.add(new JMenu("File"));
84: file.add(getNewMenuItem());
85: file.add(getOpenMenuItem());
86: file.add(getSaveMenuItem());
87: file.addSeparator();
88: file.add(getExitMenuItem());
89:
90: //image icon to open a file in a menu bar
91: JMenuItem open = new JMenuItem(createImageIcon("open.gif"));
92: open.addActionListener(new ActionListener() {
93:
94: public void actionPerformed(ActionEvent e) {
95: int value = fc.showOpenDialog(FileChooser.this);
96: if(value == JFileChooser.APPROVE_OPTION) {
97: //gets file and path
98: File file = fc.getSelectedFile();
99: String name = file.getPath();
100: try {
101: //sets file in text area
102: FileReader reader = new FileReader(file);
103: area.read(reader, "");
area.setTabSize(2);
104: //sets frame's title
105: frame.setTitle(title + " " + name);
}
106: catch(IOException ioex) {}
}
107:
108: }
});
109: menuBar.add(open);
110: return menuBar;
111: }
112: //creates menu item: new
private JMenuItem getNewMenuItem() {
113:
114: JMenuItem item = new JMenuItem("New");
item.setMnemonic('n');
115: item.addActionListener(new ActionListener() {
116:
public void actionPerformed(ActionEvent e) {
117: area.setText("");
118: }
119: });
return item;
120: }
121: //creats menu item: open
122: ImageIcon openIcon = createImageIcon("open.gif");
private JMenuItem getOpenMenuItem() {
123:
JMenuItem item = new JMenuItem("Open", openIcon);
124: item.setMnemonic('o');
125: item.addActionListener(new ActionListener() {
126:
127: public void actionPerformed(ActionEvent e) {
128: int value = fc.showOpenDialog(FileChooser.this);
129: if(value == JFileChooser.APPROVE_OPTION) {
130: //gets file and path
131: File file = fc.getSelectedFile();
132: String name = file.getPath();
133: try {
134: //sets file in text area
135: FileReader reader = new FileReader(file);
136: area.read(reader, "");
137: area.setTabSize(2);
138:
139:
140:
141:
142:
143:
385
เร่ิมตน การเขยี นโปรแกรมดวย Java
144: //sets frame's title intro. to Java (FEU.faa)
frame.setTitle(title + " " + name);
145: }
146: catch(IOException ioex) {}
}
147: }
});
148: return item;
149: }
150: //creates menu item: save
151: ImageIcon saveIcon = createImageIcon("save.gif");
private JMenuItem getSaveMenuItem() {
152:
JMenuItem item = new JMenuItem("Save", saveIcon);
153: item.setMnemonic('s');
154: item.addActionListener(new ActionListener() {
155: public void actionPerformed(ActionEvent e) {
int value = fc.showOpenDialog(FileChooser.this);
156: if(value == JFileChooser.APPROVE_OPTION) {
157: //gets file and path
File file = fc.getSelectedFile();
158: String name = file.getPath();
try {
159: //opens file in text area
160: FileWriter writer = new FileWriter(file);
area.write(writer);
161: //sets frame's title
frame.setTitle(title + " " + name);
162: }
163: catch(IOException ioex) {}
}
164:
165: }
});
166: return item;
}
167:
168: //creates menu item: exit
private JMenuItem getExitMenuItem() {
169:
JMenuItem item = new JMenuItem("Exit");
170: item.setMnemonic('x');
171: item.addActionListener(new ActionListener() {
172: public void actionPerformed(ActionEvent e) {
System.exit(0);
173:
174: }
});
175: return item;
}
176:
177: public static void main(String[] args) {
//schedules a job for the event-dispatching thread:
178: //creating and showing this application's GUI.
179: javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
180: setGUI();
}
181: });
182:
}
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201: }
11.7.1 การใช action ใน menu
เนอ่ื งจากวา item ใน menu จะเปน ตัวกาํ หนดการสนองตอบผานทาง interface ตัวอน่ื เชน ปมุ
ใน tool bar ไดดังน้นั เราอาจเลอื กที่จะกาํ หนดใหมี action สาํ หรับเหตกุ ารณที่อาจเกดิ ขนึ้ ผา น
ทาง action object หลงั จากนน้ั ก็เพิ่ม action น้เี ขาสู menu ตอไป
Action exitAction = new AbstractAction("Exit") {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
};
386
บทที่ 11: GUI และ Event Handling intro. to Java (FEU.faa)
และเราก็เปลย่ี นการเพิม่ component เขาสู menu ใหเ ปน
file.add(exitAction);
การทาํ แบบนที้ าํ ใหเราไมส ามารถกําหนด hot key ใหก ับ item ใน menu ได วิธกี ารทจี่ ะทาํ ให
เราสามารถใช hot key ไดก็คอื กาํ หนดตวั แปรที่ JMenuItem ดวย action แลว จึงเพ่ิม item ตวั
น้เี ขาสู menu ตอไป เชน
JMenuItem exitItem = new JMenuItem(exitAction);
exitItem.setMnemonic('x');
file.add(exitItem);
ทง้ั สองวธิ ีเปน กระบวนการงา ย ๆ ท่ีทําให item ใน menu มกี ารสนองตอบตอ เหตุการณท่เี กิดขน้ึ
จากผใู ช ผอู า นอาจเลือกใชว ิธใี ดกไ็ ดท ีเ่ ห็นวา เหมาะสมกบั งานน้นั ๆ
11.7.2 Pop-UP Menu
Pop-up menu เปน menu ทไ่ี มไ ดผกู ตดิ กบั menu bar เชนที่เราทาํ กอ นหนาน้ี แตจ ะเปน
menu ท่โี ผลขน้ึ มาเม่อื ผใู ช activate
ภาพท่ี 11.18 pop-up menu ใน text area
การสราง pop-up menu ก็คลา ยกบั การสราง menu โดยทว่ั ไปจะตางกันตรงท่ี pop-up menu
จะไมม ี title เทา นนั้ เอง
JPopupMenu popup = new JPopupMenu();
JMenuItem item = new JMenuItem("Pop-Up One");
popup.add(item);
popup.add(exitAction);
เม่ือสรา ง pop-up menu เสรจ็ การทจ่ี ะให component ใด ๆ มี pop-up menu ดวยนนั้ เชน
จากโปรแกรมตวั อยาง เราตอ งการท่ีจะให pop-up menu เกิดข้นึ เม่อื ผูใ ชกดปุม ขวาบน mouse
ในพ้นื ท่ีของ text area เราก็ใชค ําส่งั
area.setComponentPopupMenu(addPopup());
ในท่ีนเ้ี ราสราง pop-up menu ใน method addPopup() ดงั น้นั เรากเ็ พยี งแตส ง method ตวั น้ี
ไปให setComponentPopupMenu()
public JPopupMenu addPopup() {
//code ทีเ่ หมือนกบั ทแี่ สดงกอนหนา น้ี
return popup;
}
387
เร่มิ ตนการเขียนโปรแกรมดวย Java intro. to Java (FEU.faa)
11.7.3 Accelerator ใน menu
ใน menu หลาย ๆ ตัวที่เราเคยเห็นหรือเคยใชม ากอน เราจะเห็นวา มคี าํ สงั่ ทตี่ ามหลงั item ใน
menu ในรูปแบบของ combination key เชน CTRL+O หรอื CTRL+X เปนตน key เหลานเ้ี ปน
accelerator key ท่ยี อมใหเราใชโดยไมตองเปด menu (ไมเ หมอื นกับ key mnemonic ทเี่ รา
ตอ งเปด menu กอนถงึ จะใชไ ด)
ภาพท่ี 11.19 Accelerator ใน menu
การกาํ หนดใหม ี accelerator key ใน menu กท็ ําไดง า ย ๆ เราเพียงแตใชค าํ สัง่
item.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_O, InputEvent.CTRL_MASK));
กับ menu item ท่เี ราตอ งการ แคน ีเ้ ราก็สามารถใช CTRL+O เพอ่ื เปด dialog window สาํ หรับ
การเลอื กไฟลท ่ีจะเปด โดยไมต อ งเปด menu
[ยกเวน การเลอื ก menu (disable menu item)]
ในบางครัง้ เราไมต องการใหผใู ชเลือก menu item ทยี่ งั ไมสามารถทาํ ไดจ นกวา กระบวนการใด
กระบวนการหนงึ่ ไดย ตุ ิ (หรือเรม่ิ ) กอน เชน จะทําการ save ไดก ต็ อเมอ่ื ไดเปด ไฟลเรยี บรอยแลว
วิธีการกม็ ดี ังนี้
กําหนดให menu item ของการ save ใหเปน false ดว ยคําสง่ั
saveItem.setEnabled(false);
และเพิม่ code เพอ่ื กาํ หนดใหก าร save เปน ไปไดห ลังจากการเปดไฟลแ ลว ดวยคําสง่ั
saveItem.setEnabled(true);
ภาพที่ 11.20 disable menu item
388
บทที่ 11: GUI และ Event Handling
11.7.4 JToolBar intro. to Java (FEU.faa)
JToolBar
ภาพที่ 11.21 JMenuBar
JToolBar เปน component อีกตวั หนึ่งท่ีเราสามารถนาํ มาใชเ ปนตวั เลือกทด่ี อี ีกตวั หนึ่งใหก บั ผใู ช
การสรา งกง็ าย ๆ เราเพียงแตกาํ หนด action ทเ่ี กย่ี วของกับส่งิ ทเ่ี ราตองการใหม อี ยใู น tool bar
เชน open และ save ที่เราแสดงใหด ูในภาพท่ี 11.20
JToolBar bar = new JToolBar();
bar.add(openAction);
bar.add(saveAction);
เม่ือไดแลวเรากน็ าํ tool bar ไปใสไ วใน container ของเรา
contentPane.add(bar, BorderLayout.PAGE_START);
สวน action กท็ ําคลาย ๆ กบั ทเ่ี ราไดท าํ ในสว นของ exit ดงั นี้
Action openAction = new AbstractAction("Open", openIcon) {
public void actionPerformed(ActionEvent e) {
//code for open file
}
};
Action saveAction = new AbstractAction("Save", saveIcon) {
public void actionPerformed(ActionEvent e) {
//code for save file
}
};
Tool bar ทเี่ ราสรา งข้นึ นส้ี ามารถท่ีจะนาํ ไปอยูในตาํ แหนงใดก็ได (drag-able)
ภาพท่ี 11.22 การวาง tool bar ในท่ีตาง ๆ
เพอื่ ใหผูใชรูว า ปุมหรือ icon นัน้ ๆ ใชสาํ หรับทํางานอะไร เราก็สามารถใส tooltip ใหกบั
component เหลานัน้ ได เชน ถาเราใช action object ดงั ตัวอยางทผ่ี า นมาเรากเ็ รยี กใช
389
เรม่ิ ตน การเขียนโปรแกรมดว ย Java intro. to Java (FEU.faa)
openAction.putValue(Action.SHORT_DESCRIPTION, "Open");
แตถา เราใช component อนื่ ๆ เรากเ็ รยี กใช method setToolTipText() แทน เชน
saveButton.setToolTipText("Save");
menu ท่เี ราใชเ ปน menu ที่ Java เรียกวา floatable menu ซึ่งเปน menu ทผี่ ใู ชส ามารถเลอื ก
ตาํ แหนงในการวางได แตถ า ผใู ชตองการทจี่ ะให menu อยกู บั ท่กี ต็ อ งเรยี กใช method
setFloatable() ดว ยคา false เชน
toolbar.setFloatble(false);
ภาพท่ี 11.23 non-floatable menu
Swing ยงั มี component อีกหลายตวั ท่ีเราสามารถนาํ มาใชใน application ตา ง ๆ ที่เราตองการ
พัฒนาไดอีกมากมาย การจดั วาง component ท่ีมีความซับซอ น และความหลากหลายของ
component ก็สามารถทาํ ไดง า ย ๆ ดวย layout manager ตวั อน่ื ๆ ท่ี Java ไดจ ัดไวใ ห อยา งไร
กต็ ามหนังสือเลม นี้เปน การแนะนาํ การสราง GUI ในระดบั เร่ิมตน เทา นนั้ เราคงไมส ามารถนาํ เอา
ขอ มูลทั้งหมดทเี่ ก่ยี วขอ งกับการพัฒนาโปรแกรมดว ย Swing มาแสดงใหผ อู านไดท งั้ หมด ท้งั นี้ก็
คงตองเปนหนา ทขี่ องผูอา นทจ่ี ะหาขอมูลอื่น ๆ สําหรับการสรา งโปรแกรมทต่ี อ งการ GUI ทดี่ ู
เหมาะสมและสวยงามจากทอี่ น่ื ๆ ตอไปดวยตัวเอง เชนการใช BoxLayout, GridbagLayout,
SpringLayout หรอื laytout อนื่ ๆ ท่ีสรา งข้ึนมาใชเอง
สําหรบั สว นที่เหลืออยูของหนงั สือเลมนี้เราจะแสดงถึงการสรา ง GUI ดวยการใช Netbeans 5.0
ซงึ่ เปนโปรแกรมที่ไดก ลาวไวในบททห่ี นงึ่ อยางคราว ๆ
11.8 Swing กบั Netbeans 5.0
การสรา ง application ทตี่ อ งมกี ารจัดวาง component มาก ๆ จาํ เปนที่จะตอ งมเี ครื่องมอื ทท่ี ําให
การทาํ งานดงั กลา วเปน ไปอยางงา ย และรวดเร็ว ในปจจบุ ันมเี ครือ่ งมือหลายตัวทช่ี ว ยได หนึง่ ใน
นั้นกค็ อื Netbeans 5.0
เราจะลองสรางโปรแกรมตวั อยา งทที่ ําการเปลย่ี นหนว ยการวดั จากระบบ Metric ไปสูระบบ US
(หรือจาก US ไปเปน Metric) โดยเราจะกาํ หนดใหม กี ารใช component ดงั นคี้ ือ
1. JTextField 2 ตัว
2. JRadioButton 3 ตัว (พรอมกับ ButtonGroup อีกหน่งึ ตัว)
3. JScrollBar 2 ตวั
4. JComboBox 2 ตัว
5. JPanel 2 ตัว
โดยใหโปรแกรมมหี นา ตาดังน้ี
390
บทที่ 11: GUI และ Event Handling
ภาพที่ 11.24 โปรแกรมตัวอยางทส่ี รางดวย Netbeans 5.0 intro. to Java (FEU.faa)
เรามาลองดขู น้ั ตอนการสรา งโปรแกรมตวั อยางดว ย Netbeans 5.0 ดู
1. เลอื ก File Æ New Project ภายใต Categories เลือก General ภายใต Project เลือก
Java Application แลวจงึ กดปมุ Next
2. ภายใต Project Name ใหใ ส conversion สาํ หรบั Project Location ก็ใหเ ลอื กแฟมที่
เราตองการเกบ็ project เชน D:\NetbeansProjects และภายใต Project Folder ก็ให
เปน ไปตามคาทมี่ าจาก Netbeans เอง (D:\NetbeansProjects\conversion)
3. สว นที่เหลอื อน่ื ๆ กใ็ หเ ปน ไปตามที่ Netbeans กาํ หนดหรอื ถาตองการกําหนด
package สําหรบั Main class ใหเปน อยางอนื่ เชน ที่เราใชก ใ็ ส
edu.fec.it.conversion.Main (เพราะวาเราเปน ภาควชิ า it ท่ี fec.edu)
4. กดปุม Finish
องคป ระกอบของ Netbeans IDE
Palette
Inspector Design Area Properties Window
ภาพที่ 11.25 Netbeans Window
391
เรม่ิ ตน การเขยี นโปรแกรมดวย Java intro. to Java (FEU.faa)
Design Area เปนพ้ืนทสี่ าํ หรบั การสราง GUI โดยกําหนดใหป มุ Source และ Design เปน
หนา ตางท่ีเปน code และหนา ตางทีม่ กี ารสรา งแบบ visual สว นปุมอนื่ ๆ กเ็ ปน ปุม สําหรบั การ
เลอื ก mode และการปรบั แตง การจัดวาง
Inspector เปนหนาตางท่ีรวบรวมเอา component ทงั้ หมดใน project มารวมไว โดยท่เี รา
สามารถท่ีจะเลือก component ในการออกแบบผา นทาง Inspector window ได
Palette เปน ที่รวม component ตา ง ๆ ท่ีเราสามารถนาํ มาใชใ นโปรแกรมของเราไดด ว ยการ
ลากแปะ
Properties Window เปน ทแี่ สดง property ของ component ตา ง ๆ ในโปรแกรม และเปนที่
ทเ่ี ราสามารถเปลี่ยน หรือกาํ หนดคาตาง ๆ ของ component
หลงั จากกดปุม Finish แลวเรากจ็ ะเหน็ ไฟล Main อยูภายใน IDE ทางดา นขวาของ Project tab
ข้ันตอนตอ ไปทเ่ี ราตอ งทํากค็ ือสราง Java ไฟลอ ีกตวั หน่ึงช่ือ ConversionForm ซง่ึ จะเปน ไฟล
หลักของเรา โดยเราจะกาํ หนดใหการออกแบบไฟลต วั นี้เปน การออกแบบดว ย Visual
component
1. ภายใต Project tab และ node: ที่เราสรา งข้ึน เชน edu.fec.it.conversion ใหกดปุม
ขวาบน mouse เลอื ก New Æ JFrame Form …
2. ภายใต Class Name ใหใส ConversionForm อยา ใหต ัวอกั ษรตวั แรกเปน ตัวเลก็ ท้ังน้ี
เพราะวา Java ชอบใชต ัวอกั ษรตวั ใหญข้นึ ตนชอ่ื class
3. สว นอ่นื ๆ ใหเปน ไปตามท่ี Netbeans กาํ หนด กดปมุ Finish เรากจ็ ะเหน็ พน้ื ทส่ี ีเทาที่
พรอ มใหเราสรา ง GUI ทเ่ี ราตอ งการตอไป
ตอ ไปก็เปน ขั้นตอนการสรา ง Form ทีเ่ ราตอ งการ ซง่ึ มีลําดบั ดังน้ี
1. จาก Component Palette ทางดา นขวาของ IDE ลาก JPanel เขาสู Form โดยลากไป
ทางดา นซายบนจนกวาจะเห็นเสนประสองเสน ทางดา นบนและทางซาย ซงึ่ เสนประทัง้
สองเปน ตวั ชว ยในการวาง component (ท่ี GroupLayout manager2 ใช) กําหนดให
ขนาดของ JPanel มขี นาดประมาณครึ่งหน่งึ ของ Form หลงั จากนัน้ ก็สรา ง JPanel อีก
หน่งึ ตวั วางไวท างขวาของตวั แรก
2. เพื่อใหท ้ังสอง JPanel มีขนาดท่ีเทากบั เราก็เลือก JPanel ตวั หน่ึง (เชน ตวั ทางซา ย)
กดปุม Shift แลวจงึ เลือก JPanel ทางขวา Æ กดปุม ขวาบน mouse เลอื ก Same Size
แลว จึงเลือก Same Width
3. ถึงแมวา เราไดส ราง JPanel 2 ตัวแลวแตเราก็มองไมเหน็ นอกเสียจากวาเราจะนาํ
mouse ไปวางบน JPanel ทง้ั สอง (JPanel เปน container ท่ีใชจดั เก็บ component
อกี ทหี น่งึ ) และเพอื่ ใหม องดแู ลวสวยงามเราก็จะสรา ง border ใหกับ JPanel ทั้งสอง
4. เลือก JPanel ตวั ใดตัวหนึ่ง (เราไมไ ดเ ปลย่ี นแปลงสิง่ ที่ Netbeans กําหนดดังนนั้ ช่อื
ของ component กจ็ ะเปน jPanel1 และ jPanel2) เม่ือเราเลือก jPanel1 เรากจ็ ะเห็น
Properties windows ทางดานขวาลางของ Netbeans (ถดั จาก Palette) ภายใต
border properties กดปมุ … เลือก TitledBorder ภายใต Title ใส Metric System ใน
สวนของ Border กดปมุ … เลอื ก LineBorder พรอ มกับ check ชอง Rounded
Corners กดปมุ OK 2 คร้ัง
5. ทําอยา งเดยี วกนั น้ีกับ jPanel2 ดว ยชอ่ื border เปน US System
2 Netbeans 5.0 โดย Matisse ใช GroupLayout manager เปนตวั จดั วาง component
392
บทที่ 11: GUI และ Event Handling intro. to Java (FEU.faa)
ภาพท่ี 11.26 JPanel ท่ีเราสรา งขึ้นจาก Netbeans
จากภาพท่ี 11.26 ผูอา นจะเหน็ วามีสญั ลักษณท ค่ี ลาย ๆ กับตวั H บน JPanel ท้งั สอง ซง่ึ
เปน ตวั บง บอกถึงความมขี นาดทเี่ ทากนั ของทัง้ สอง component
ลาํ ดับตอ ไปก็เปนการใส component ตัวอ่นื ๆ เชน JScrollBar, JTextField, และ
JComboBox
1. เลือก JTextField จาก Palete วางไวใน jPanel1 ตามดว ย JScrollBar และ
JComboBox จดั ขนาดใหเหมาะสมกับพื้นท่ี
2. ทําอยา งเดยี วกนั กบั jPanel2
3. ใน JTextField ทงั สองตวั เปลย่ี นคา text ใน Properties ใหเปน 0 เลอื ก Font และสี
ของ text ตามใจชอบ
4. ในการจดั วาง JScrollBar ครัง้ แรกนนั้ Netbeans จะกาํ หนดใหเปน ไปในแนวตงั้ เราก็
เปล่ยี นใหเปน แนวนอนใน Properties ดวยการเลอื ก HORIZONTAL ใน orientation
พรอ มกับกาํ หนดใหค า maximum เปน 10000 และคา minimum เปน 0 สวน
unitIncrement น้ันเรากใ็ หเ ปน คา default คอื 1 (เทากนั ทง้ั สอง scroll bar)
5. สวนเสน แนวนอนที่เหน็ กเ็ ปน JSeparator ทไ่ี ดจ ดั วางไวเฉย ๆ
6. ตอไปกล็ าก JRadioButton มาวางไวสามตัว พรอมกับเปล่ียนคา text ใหเปน
Distance, Weight และ Temperature ตามลาํ ดบั โดยกาํ หนดให Distance มีการ
check ไวกอนลว งหนา ดวยการกาํ หนดคาใน Properties: selected
7. และเพ่อื ใหการกดปุม ใหเ ปน การเลอื กปมุ ใดปมุ หนง่ึ เทาน้นั เราตองลาก ButtonGroup
จาก Palete มาวางไวใ น Form ที่ใดท่ีหน่ึง ซึ่งถา เราดใู น Inspector window ทาง
ดานซายลางของ IDE เรากจ็ ะเหน็ วา ButtonGroup อยูภ ายใต node: Other
Components หลงั จากนั้นเรากเ็ ลือก jRadioButton1 ภายใน Proiperties window
กาํ หนดคา buttonGroup ใหเปน buttonGroup1 ทําอยางเดียวกันนี้กับ
jRadioButton2 และ jRadioButton3
กระบวนการที่เราทาํ ก็จะทําใหเ ราไดหนาตางในรปู แบบของ GUI ทสี่ วยงามพอสมควร สาํ หรับ
ลูกเลน อนื่ ๆ ทตี่ องการกส็ ามารถทําไดใน Properties window
393
เรม่ิ ตน การเขียนโปรแกรมดว ย Java
TitledBorder JTextField JScrollBar
JRadioButton ใน ButtonGroup JSeparator JComboBox intro. to Java (FEU.faa)
ภาพที่ 11.27 component ตาง ๆ ในโปรแกรมตวั อยา ง
ขั้นตอนตอไปทเี่ ราตองทาํ กค็ อื การกาํ หนดการสนองตอบตอ เหตกุ ารณท ผี่ ใู ชเ ลือก แตก อ นท่เี รา
จะไปถงึ ตรงนนั้ เราตอ งกําหนดคาตาง ๆ ที่มอี ยใู น JComboBox ทัง้ สามตวั กอ น เราอาจที่จะเลือก
ทําใน Properties window กไ็ ดซ ึง่ โดยการกําหนดของ Netbeans แลว คา เหลาน้จี ะเปน item1
– item4 เราจะลบคาเหลานท้ี ง้ิ ไป (ดว ยการกดปมุ … ภายใต Properties window ของ
jComboBox1 (2) ในสว นของ model เรากจ็ ะได pop-up window ทีแ่ สดงคา item1 – item4
เลอื ก item ดงั กลา วแลว กก็ ดปมุ Remove) แตจ ะไปกาํ หนดใน constructor แทนดัง code ท่ี
เหน็ นี้
public ConversionForm() {
initComponents();
allocateSpace();
distanceInit();
}
private void allocateSpace() {
mdUnit = new Unit[3];
mwUnit = new Unit[3];
udUnit = new Unit[4];
uwUnit = new Unit[3];
}
private void distanceInit() {
mdUnit[0] = new Unit("Centimeters", 0.01);
mdUnit[1] = new Unit("Meters", 1.0);
mdUnit[2] = new Unit("Kilometers", 1000.0);
for(int i = 0; i < mdUnit.length; i++)
jComboBox1.addItem(mdUnit[i].getDescription());
udUnit[0] = new Unit("Inches", 0.0254);
udUnit[1] = new Unit("Feet", 0.305);
udUnit[2] = new Unit("Yards", 0.914);
udUnit[3] = new Unit("Miles", 1613.0);
for(int i = 0; i < udUnit.length; i++)
jComboBox2.addItem(udUnit[i].getDescription());
}
Constructor: Conversion() เปน สวนที่ Netbeans ไดส รา งข้ึนพรอมทัง้ method
initComponents() ซ่งึ เราไมค วรทจี่ ะไปแตะตอ ง สวน method allocateSpace() และ
distanceInit() น้ันเราสรา งข้ึนมาเอง
394
บทที่ 11: GUI และ Event Handling intro. to Java (FEU.faa)
เราไดก าํ หนดใหมี class Unit เปน class ท่ีเราจะใชใ หเ ปน หนวยของการวดั สองตัวคือ Distance
และ Weight สว น Temperature นน้ั เราจะกาํ หนดตา งหาก การสรา ง class Unit ขน้ึ มาใชท าํ ให
การเขียน code รองรับการเปลย่ี นหนวยทผี่ ูใชเ ลือกทําไดง า ยขนึ้ (เราจะมาดกู นั ตอไป) ผอู า นจะ
เหน็ วาเราเรยี ก method allocateSpace() และ method distanceInit() หลงั จากการเรยี ก
method initComponents() ทง้ั นกี้ เ็ พราะวา component ตา ง ๆ ทเี่ ราลากไปแปะไวใน form จะ
อยูใน method นี้ (ดู code ดวยการกด Source tab ใน IDE)
ภายใน method allocateSpace() เราสราง object จาก class Unit 4 ตวั คือ mdUnit, mwUnit,
udUnit และ uwUnit โดยทต่ี วั แรกเปนตวั เกบ็ ระยะทางในหนว ย Metric ตัวทส่ี องเกบ็ นาํ้ หนกั ใน
หนว ย Metrics สว นสองตวั สุดทายเปน การเกบ็ ระยะทางและนาํ้ หนักในหนว ย US ตามลาํ ดับ
ภายใน class Unit เรากาํ หนดใหมีองคป ระกอบดังน้ี (สรา งใน package เดยี วกับ
ConversionForm.java ดูภาพท่ี 11.28 ประกอบ)
เราสรางเอง
ภาพที่ 11.28 ไฟลตา ง ๆ ทีอ่ ยูใ น package: edu.fec.it.conversion
public class Unit {
private String description;
private double multiplier;
/** Creates a new instance of Unit */
public Unit() {
}
public Unit(String description, double multiplier) {
this.description = description;
this.multiplier = multiplier;
}
public String getDescription() {
return description;
}
public double getMultiplier() {
return multiplier;
}
}
description เปน ตวั แสดงการวดั เชน Kilograms สวน multiplier เปน ตวั คณู ของการเปล่ยี น
หนวย จากหนว ยหน่ึงไปยังอกี หนวยหนึง่ method getDescription() สง คา description กลับ
สว น method getMultiplier() กส็ งคา ตวั คูณกลับ
ภายใน method distanceInit() เรากก็ ําหนดคาตา ง ๆ ทต่ี องการใหกับท้งั mdUnit และ
mwUnit พรอ มท้ังนาํ ขอมูลเหลา น้เี ขา สู jComboBox1 (Metric) และ jComboBox2 (US)
395
เรม่ิ ตน การเขยี นโปรแกรมดว ย Java intro. to Java (FEU.faa)
สาํ หรับขอมูลใน jComboBox1 และ jComboBox2 ของ jRadioButton2 นน้ั เรากก็ ําหนดจาก
method weightInit() ซึ่งมีการกําหนดดังนี้
private void weightInit() {
mwUnit[0] = new Unit("Grams", 0.001);
mwUnit[1] = new Unit("Kilograms", 1.0);
mwUnit[2] = new Unit("Tons", 1000.0);
for(int i = 0; i < mwUnit.length; i++)
jComboBox1.addItem(mwUnit[i].getDescription());
uwUnit[0] = new Unit("Ounces", 0.02834949);
uwUnit[1] = new Unit("Pounds", 0.45359291);
uwUnit[2] = new Unit("Short Tons", 907.19404881);
for(int i = 0; i < uwUnit.length; i++)
jComboBox2.addItem(uwUnit[i].getDescription());
}
ในคร้งั แรกทโ่ี ปรแกรมทาํ งานนน้ั ขอ มูลจะมีอยใู น jComboBox1 และ jComboBox2 ทเ่ี ปนหนวย
ของการวัดระยะทางเทานนั้ เพราะเรากําหนดไวใ น constructor แตถ า ผใู ชเลอื ก jRadioButton2
หรอื jRadioButton3 เราก็จะกาํ หนดคาเหลานใ้ี หด วยการใส code สาํ หรบั การสนองตอบตอ การ
กระทําดงั กลา วเขา สู jComboBox2 และ jComboBox3 ตอ ไปดงั น้ี
เลือก jRadioButton2 (Weight) Æ กดปมุ ขวา เลือก Events Æ Action Æ actionPerformed
เราก็จะได method:
private void jRadioButton2ActionPerformed(java.awt.event.ActionEvent evt) {
jComboBox1.removeAllItems();
jComboBox2.removeAllItems();
weightInit();
}
ซงึ่ จะเปน method ทีไ่ มมอี ะไรอยเู ลย เราตองใส code เองซ่งึ เรากจ็ ะตอ งทาํ การกําหนดคา
ใหก ับ jComboBox ตวั นโ้ี ดยขน้ั ตอนแรกเรากล็ บขอมลู เดิมออกกอ นดวยการเรียก method
removeAllItems() หลงั จากน้ันเรากใ็ สข อ มลู ใหมเขา ไปดว ยการเรยี กใช method weightInit()
และในสว นของการเลอื ก jRadioButton3 เราก็เขยี น code รองรบั ดังนี้
private void jRadioButton3ActionPerformed(java.awt.event.ActionEvent evt) {
jComboBox1.removeAllItems();
jComboBox2.removeAllItems();
jComboBox1.addItem("Celsius");
jComboBox2.addItem("Fahrenheit");
}
ณ เวลาน้ีเรากไ็ ดท ําการใสขอมลู ใหกบั JComboBox ท้งั สองตวั ดว ยเง่อื นไขจากการกําหนดจาก
โปรแกรมหนงึ่ สวน คอื ผานทาง constructor และผา นทางเงอื่ นไขจากผูใ ชอ ีกสองสว นคอื เม่อื
เลือก Weight และเม่อื เลอื ก Temperature
สําหรับการสนองตอบตอการเลือก jRadioButton1 นั้นเรากท็ าํ คลาย ๆ กนั คือ ลบขอ มลู เกา ออก
นาํ ขอ มูลใหมเ ขา ใสแทน
private void jRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {
jComboBox1.removeAllItems();
jComboBox2.removeAllItems();
distanceInit();
}
396