Lab Event Handling
แล็บนี้เราจะลองทำ โปรแกรมคูณเลขง่ายๆดู
ตอนที่ 1
โจทย์
ห้องสมุดเล็กๆแห่งหนึ่งรับหนังสือแต่ละครั้งเป็นลังหลายๆลัง
ถ้าให้แต่ละลังมีจำนวนหนังสือเท่ากัน
ผู้ดูแลห้องสมุดต้องการให้นักเรียนทำโปรแกรมง่ายๆให้เขาใช้งานในการรับของหนึ่งครั้งดังนี้
- มีช่องให้ใส่จำนวนลังในการส่งครั้งนั้น
- มีช่องให้ใส่จำนวนหนังสือต่อหนึ่งลัง
- มีปุ่มให้กด "คำนวณจำนวนหนังสือทั้งหมด"
- มีที่แสดงผลลัพธ์ ว่าจำนวนหนังสือทั้งหมดเป็นเท่าไร
ตัวอย่างโปรแกรม เป็นดังรูป
โดยจะมีช่องขาวๆ
ที่พิมพ์ลงไปได้ (เรียกว่า JTextBox) สองช่อง เมื่อพิมพ์ลงไปแล้วกดปุ่ม
(ปุ่มนั้นสร้างด้วยคลาส JButton) Calculate Total จะปรากฎว่า ผลคูณจะแสดงออกมาใน JTextBox
ที่พิมพ์ลงไปไม่ได้ ส่วนตัวหนังสือที่อธิบายต่างๆก็เป็น JLabel หมด ให้วินโดวมีขนาด 354, 112
ก่อนอื่น
จงทำวินโดว์ออกมาให้ได้หน้าตาแบบนี้ก่อน ไม่ต้องขนาดเท่าเป๊ะ
ไม่ต้องสัดส่วนเหมือนเป๊ะ ใช้การวางเลย์เอ้าท์ทำให้ได้รูปร่างก็พอ
ยังไม่ต้องคำนวณ
ให้เริ่มเขียนคลาส จากโครงนี้ (นี่เป็นโครงของโค้ดที่เอามาจากหนังสือเรียนของ dietel) เปลี่ยนโค้ดได้ตามใจ สามารถลบโค้ดเดิมทำใหม่หมดได้ แต่ชื่อต่างๆขอให้คงไว้
- ให้ค่าเริ่มต้นใน JTextField เป็น 0 นะ
- JTextField นั้นเราสามารถเซ็ตคุณสมบัติต่างๆได้เหมือน JLabel เลย ไปอ่านใน slide กับ API ให้ดี
- ต้องทำให้ สิ่งที่พิมพ์ไปใน textfield นั้นอยู่ด้านขวาของตัว textfield
- อย่าลืมว่าต้องให้ edit ผล ไม่ได้ (ใช้เมธอด setEditable)
- JButton สามารถ setText และsetBounds หรือ setLocation, setSize ได้ เพื่อวางตำแหน่ง
- การ
setLayout(new FlowLayout()) หรือ layout แบบอื่นๆ จะทำให้
ของต่างๆปรากฎบนจอได้ โดยไม่ต้อง setBounds
แต่ว่าจะทำให้กำหนดขนาดได้ลำบากนิดหนึ่ง
เอาล่ะ ถ้าทำเสร็จแล้ว ยังมีต่อ คราวนี้เราจะมาทำให้มันคำนวณจริงๆซะที พอกดปุ่มปั๊บ ให้มันคำนวณแล้วโชว์ผลปุ๊บ
ทำได้เลย ทำเสร็จแล้วต่อตอนที่ 2
ตอนที่ 2
เพิ่มเติมจากตอนที่ 1 - ให้
เมื่อ ผู้ใช้ พิมพ์ข้อมูลลงไปเป็นครั้งที่ไม่ใช่ครั้งแรก ใน JTextField ตัวใดตัวหนึ่งที่รับ
input แล้ว ตัว JTextField ที่โชว์คำตอบ ต้องเคลียร์ด้วย
เพื่อป้องกันการสับสนในคำตอบ
- พอกด Calculate Total คำตอบใหม่ถึงจะโผล่มา
ตอนที่ 3
จะสังเกตว่า ถ้าเราเกิดใส่อะไรก็ตามที่ไม่ใช่ตัวเลขลงไปในช่อง input เช่น
แล้วไปกด calculate จะปรากฏว่ามี error message เกี่ยวกับ java.lang.NumberFormatException ขึ้นที่
console เต็มไปหมด หรือถ้ารันจากจาร์เลย พอกด Calculate ใน executable jar
ก็จะไม่เกิดอะไรขึ้น นี่เป็นเพราะว่า
เราคาดหวังว่าจะได้แต่สตริงที่แปลงเป็นตัวเลขได้ เข้ามาที่ input
ถ้าแปลงไม่ได้ โปรแกรมก็ทำอะไรต่อไปไม่ได้นั่นเอง
งั้นเรามาเปลี่ยนแปลงโปรแกรมหน่อยดีกว่า โดย
- ถ้าเกิดกด Calculate Total ไปในตอนที่อินพุต(ไม่ว่าของช่องใดก็ตาม) เป็นสิ่งที่ไม่สามารถเปลี่ยนเป็นจำนวนเต็มได้
ให้โปรแกรม pop up Warning Dialog ออกมา บอกให้ผู้ใช้โปรแกรมเปลี่ยนค่าใน
textfield ใหม่อีกครั้ง ตามรูปนี้
·
การตั้งชื่อ project ให้ตั้งชื่อตามรูปแบบต่อไปนี้
LAB##_<รหัสนิสิต> เช่น LAB08_5270271821
สําหรับแต่ละไฟล์ที่เขียน ให้ตั้งชื่อไฟล์ที่เป็น .java
ให้ตรงกับชื่อของ class ในไฟล์นั้นๆ
และให้ขึ้นต้นไฟล์ด้วยข้อมูลเกี่ยวกับตัวเองดังนี้
/*
* LAB##
* รหัสนิสิต
* ชื่อ-นามสกุล
* หมายเลขห้อง
หมายเลขเครื่องที่ใช้
*/
เช่น
/*
* LAB08
* 5270271821
* นายเพื่อ สกุลไทย
* หอง
111 เครื่อง 101
*/
·
ไฟล์ที่ส่ง
ให้ export ออกมาในรูปแบบ executable jar (ดูวิธีทำที่ด้านล่าง)โดยให้มี
source code (.java) อยู่ภายใน jar ด้วย และให้ตั้งชื่อตามรูปแบบดังต่อไปนี้ (โดยให้ใช้อักษรพิมพ์ใหญ่/เล็กในรูปแบบเดียวกับที่แสดงในตัวอย่างด้านล่าง)
LAB08_<รหัสนิสิต>.jar
• E-mail ที่ส่ง ให้ตั้งชื่อ Subject ของ E-mail ตามรูปแบบดังต่อไปนี้ โดยให้ใช้ตัวอักษรพิมพ์ใหญและเล็กในรูปแบบ
เดียวกับที่แสดงในตัวอย่างด้านล่าง
LAB08_<รหัสนิสิต> เช่น
รหัสของผม(TA) คือ 5270271821 ก็จะมี Subject ของ
E-mail เป็น LAB08_5270271821
*** ถ้าหากมี
comment หรืออะไรเพิ่มเติม ให้เขียนไว้ใน body
ของ E-mail ห้ามเขียนไว้ใน Subject
ของ E-mail ***
• กําหนดส่งคือ
วันศุกร์ ที่ 13 สิงหาคม เวลา 0:00 AM (เวลาเที่ยงคืนของคืนวันพฤหัส)
*** ห้ามลอก ถ้าพบจะให้ 0
คะแนนในครั้งนั้นๆ ***
วิธีทำ executable jar (คือจาร์ไฟล์ที่ double click แล้วรันเลย)
- ขึ้นแรก Right Click ตัวโปรเจ็ค แล้วเลือก export ตาม pop up menu ที่โผล่ขึ้นมา
- จากนั้น เลือก jar ดังรูป
- กด Next ไป
- วินโดว์จะเปลี่ยนเป็นอีกหน้า
- ให้เลือกติ๊กถูกไฟล์ที่จะ export ทั้งหมด แล้วก็เลือก Export generated class files and resources ซึ่งนี่คือคำสั่งในการเอาคลาสไฟล์ใส่จาร์ เพื่อให้รันได้
- สำหรับการส่งงาน จะต้องเลือกติ๊ก Export java source files and resources ด้วย เพราะจะได้มีโค้ดติดมาให้อาจารย์ตรวจ
- เลือกที่ที่จะให้ jar ไฟล์ไปอยู่
- เลือก compress ไฟล์ได้ด้วย
- จากนั้นกด Next
- ถึงตรงนี้จะมีหน้าให้เลือก export files with compile warnings ก็เลือกซะ
- ตรง build project if not built automatically ก็ติ๊กไว้ด้วย
- จากนั้นกด Next
- ตอนนี้เราจะอยู่ในหน้า
JArR Manifest Specification นี่คือการกำหนด Manifest file
ซึ่งเป็นไฟล์ที่ตัวจาร์จะอ่านเวลาเราดับเบิ้ลคลิ๊ก โดยไฟล์นี้จะบอกจาร์ว่า
ต้องไปรันคลาสเมนของโปรแกรมที่ไหน
- เลือก Generate the manifest file
- จะ seal ก็ได้ แต่อันนี้ไม่เกี่ยวกับบทเรียน
- ด้านล่าง เราเลือกคลาสที่มีเมธอด main ได้จากการ Browse
- พอเลือก main class แล้วก็กด Finish
ไกด์ สำหรับคนที่ทำยังไม่ได้จริงๆ (ไม่ควรดู นอกจากจะไม่ไหวจริงๆเท่านั้น)
ตอนที่ 1
สำหรับคนที่ยังงงๆหรือทำไม่ได้
ผมจะค่อยๆสอนไปทีละขั้นนะ ขอย้ำอีกทีว่า ให้คิดไปด้วย
อย่าเอาแต่ทำตามอย่างเดียว ไม่งั้นเดี๋ยวไม่เก็ตนะ
ถ้าเราต้องการกดปุ่ม (หรือกดอะไรก็ตาม แล้วให้โปรแกรมทำโน่นนี่)
- เราต้องสร้าง ตัวฟังเหตุการณ์ (Listener) ขึ้นมา
- ตัวฟังมีหลายประเภท สำหรับที่ฟังการกดปุ่มได้ เรียกว่า actionListener
- เอาตัวฟังไปแปะกับปุ่มที่เราต้องการให้ทำงาน
- จากนั้นก็เขียนโค้ดของตัวฟัง ว่าพอมันฟังอยู่แล้วมีอะไรเกิดขึ้น (เช่นปุ่มถูกคลิก) ให้ทำอะไรบ้าง
เอาล่ะ
สำหรับการสร้างตัวฟัง เพื่อจะฟังปุ่มนั้น เราใช้ตัวฟังประเภท
actionListener (ตัวฟังที่ฟังเหตุการณ์อย่างเช่นการติ๊กถูกผิดในช่อง
จะเป็นประเภทอื่น เรียกไม่เหมือนกัน)
ซึ่งเราสามารถสร้างตัวฟังแล้วไปแปะกับปุ่มได้เลย
ใช้โค้ดนี่
calculateJButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event){
// โค้ดที่จะรันเมื่อ
ตัวฟังรู้ว่ามีปุ่มถูกกด
}
} );
- นี่หมายถึง ปุ่ม calculateJButton นี่ แปะ ActionListener object ไปกะมัน โดยใช้เมธอด addActionListener
- แล้วไอ้ตัว ActionListener
object ที่สร้างขึ้นนี่ ก็มีเมธอด actionPerformed ที่จะรัน
เมื่อได้รับฟังสัญญาณจากสิ่งที่ตัว ActionListener แปะอยู่
- เมธอด ต้อง actionPerformed เท่านั้น ถึงจะรับฟังการ "กดปุ่ม" ได้
- event
นั้น จะถูกสร้างเป็น ActionEvent object ขึ้นมาเองโดยจาวาเมื่อปุ่มถูกกด
เราสามารถเอาตัวแปร event มาดึงข้อมูลเกี่ยวกับการกดเมาส์ครั้งนั้นได้ด้วย
แต่ว่าในที่นี้ก็ไม่ได้ใช้งานอะไรน่ะนะ
- ActionListener , actionPerformed, ActionEvent พวกนี้ จาวา นิยามไว้อยู่ก่อนแล้ว เราแค่ใช้ให้ถูกเท่านั้นก็พอ
- วิธีเขียนแบบ new อะไรขึ้นมา แล้วนิยามเมธอดของมัน ณ ตรงนั้นเลย แบบนี้ เรียกว่า การใช้ anonymous inner class
- สมัยก่อน
ใช้วิธี สร้างคลาสที่ extends ActionListener ขึ้นมาต่างหาก
แล้วเขียนเมธอด actionPerformed ในคลาสนั้น จากนั้นตอนเอามาแปะกับปุ่มก็
new คลาสนั้น แทน ActionListener แต่ว่า ผมว่า นิยามไปในโค้ดแบบ anonymous
inner class น่าจะสะดวกกว่านะ เพราะไม่ต้องสร้างคลาสขึ้นมาใหม่ต่างหากเลย
เราแค่นิยามว่า ไอ้ ActionListener object ที่ถูกสร้างขึ้นใหม่นี้
จะมีโค้ดข้างในอะไรบ้าง แค่นั้นเท่านั้น
หลักๆน่าจะเท่านี้ละ ทีนี้ก็เหลือแค่ให้เราทำการคำนวณให้ได้เท่านั้น ผมจะ hint ให้นิดหน่อยก็แล้วกันนะ
- ใช้เมธอด getText เอา text ที่อยู่ใน textbox ออกมาเป็น String ได้
- อย่าลืม ตัวเลขที่เป็น String จะต้องทำให้เป็น ตัวเลขซะก่อน ถึงจะเอามาคำนวณได้ เคยทำตอนเรียนจาวาแล้วนะ มีเมธอดอยู่นี่นะ
- ในการจะพิมพ์ตัวเลข ลง textbox ก็จะทำไม่ได้ เพราะพิมพ์ได้แค่ String ดังนั้น จะต้องเปลี่ยนเลขที่คำนวณแล้ว ให้เป็น String อีกที
- มีเมธอด String.valueOf( .. ) ให้ใช้นะ
ไกด์ ตอนที่ 2
เอาล่ะ หลักการยังเหมือนเดิม ในเมื่อเราจะทำให้ เมื่อ คนพิมพ์ลงไปในช่อง input แล้ว text ในช่องแสดงผลหายไป
เราก็ทำได้ โดยหลักการดังนี้
- ตัว JTextField เมื่อมีการพิมพ์อะไรลงไป จะเกิด KeyEvent object ขึ้น
- เราก็แค่เอาตัวฟังที่ฟัง
event ชนิดนี้ได้ (KeyListener) ไปแปะกับ JTextField
แล้วเขียนโค้ดในเมธอดของตัวฟังนั้น (เมธอดสำหรับฟังการกดคีย์ ชื่อ
keyPressed(KeyEvent event))
- บอกนิดนึง ตอน new น่ะ ไม่ได้ใช้ new KeyListener() นะ แต่ใช้ new KeyAdapter() ไม่เหมือนกับตอนใช้ ActionListener
- ทั้งนี้เพราะว่า KeyListener
นั้น จริงๆแล้วมีหลายเมธอด ถ้าเราจะเขียนโค้ดภายในของ KeyListener
ที่สร้างแบบ anomymous inner class เอง จะต้องเขียนทุกเมธอด
เนื่องจากจาวาบังคับไว้กับ Listener ทุกแบบ (ตอนที่ใช้ ActionListener
นั้น ActionListener ถูกนิยามให้มีแค่เมธอดเดียว ก็เลย addActionListener
ได้เลย ไม่ต้องกลัวเขียนหลายเมธอด)
- แต่ว่า ถ้าใช้ KeyAdapter จะเลือกนิยามโค้ดของเราแค่หนึ่งเมธอดหรือกี่เมธอดก็ได้
ไกด์ ตอนที่3
ข้อนี้เป็นการจัดการกับโค้ดตรงที่เราคิดว่าอาจเกิดปัญหา
error หรือ ....Exception ในขณะที่รันอยู่ (error เพราะว่าแปลงเป็น
integer ไม่ได้ )
วิธีการจัดการกับปัญหาประเภทนี้ คือ ตรงโค้ดที่เราสงสัย หรือคาดว่า จะเกิด error ขึ้นนั้น ให้เราเขียนครอบโค้ดส่วนนั้น
ด้วย try block ดังตัวอย่างข้างล่างนี้
try{
// โค้ดส่วนที่ทำให้เกิด error
}catch (Exception e ){
//ถ้าเกิด error ขึ้นจริง โค้ดจะมาทำในนี้ ซึ่งในนี้จะเป็นส่วนที่เราเขียนโค้ดจัดการกับ error หรือเปิด dialog เตือนผู้ใช้
// โปรแกรมได้
}
- ทบทวนกันอีกหน่อย Exception e คือ ตัวแปร e ใช้เก็บออบเจ็กต์ Exception โดย
- เมื่อมี
error เกิดขึ้น error จะอยู่ในรูปของ Exception object
และจะถูกพยายามโยนออกไปนอกเมธอด แต่ถ้ามี try-catch จับไว้
เราก็จะเรียก error ตัวนั้นตามที่ catch ตั้งชื่อรอไว้ นั่นคือ e
เราสามารถนำ ข้อมูล ที่มากับ e ไปใช้ต่อได้ ขึ้นอยู่กับโปรแกรม
- ถ้ามี error โค้ดก็จะมาทำในส่วนที่ catch ทำรอไว้ แต่ถ้าไม่มี โค้ดใน catch ก็จะไม่ถูก execute
- สำหรับการสั่งเปิด วินโดว์ ที่เป็น error message ขึ้นมานั้น ขอให้นิสิตไปดูวิธีใช้ JOptionPane ใน java.sun.com