The words you are searching are inside this book. To get more targeted content, please make full-text search by clicking here.

Introduction to Programming Java Language

Discover the best professional documents and content resources in AnyFlip Document Base.
Search
Published by ปิติ เกตุ, 2021-03-22 04:12:52

Introduction to Programming Java Language

Introduction to Programming Java Language

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


Click to View FlipBook Version