วันจันทร์ที่ 19 ธันวาคม พ.ศ. 2554

Java : Designing a Swing GUI in NetBeans IDE

        บทความนี้เหมาะสำหรับผู้ที่อยากจะลองเขียน Java Swing Application ด้วยการใช้ Tool ลากวาง ที่ Netbeans มีมาให้ หรือใครก็ตามที่ยังเขียนแบบ Code อย่างเดียวอยู่ อาจจะทำให้มีความรู้สึกว่า Java ทำไมยากจัง ไม่มี Tool ลากวางเหมือน .Net บ้างเหรอ ซึ่งจริง ๆ ใน Netbeans มีมานานมากแล้วครับซึ่งก็คงไม่ใช่เรื่องใหม่แน่นอน แต่ผมเห็นว่ามันคงจะเป็นการเริ่มต้นที่ดี สำหรับผู้ที่ยังไม่เคยลองใช้ Tool นี้มาก่อน(แล้วจะติดใจครับ) แต่อย่างไรก็ตาม การทำความเข้าใจใน Code ที่ตัว Tool ได้ Generate มาให้นั้น ก็ถือว่าเป็นสิ่งที่ดีครับ เพราะมันก็เหมือนเป็น Framework ตัวหนึ่ง ซึ่งวางโครงสร้างของการเขียน Code มาให้อยู่ในกรอบอย่างมีรูปแบบ ทำให้เราเข้าใจแนวคิดในการที่จะ Design โปรแกรมด้วย
     
        1. หากใครยังไม่ได้ติดตั้ง Netbeans ให้ติดตั้งเสียก่อน โดยดาวน์โหลดได้จาก http://netbeans.org/downloads/ ซึ่งทาง Netbeans บอกว่าต้องใช้ Version 6.9/7.0 และ JDK Version 6 ขึ้นไป ซึ่งในบทความนี้ใช้ Netbeans 7.0.1 และ JDK Version 7

        2.  New Project...
                2.1 เมื่อติดตั้งแล้วให้เปิด Netbeans ขึ้นมา ไปที่ File-->New Project...




                2.2 เลือก Categaories: Java , Projects: Java Application จากนั้นกด Next >


                2.3 ใส่ Project Name: GPADemo แล้วติ๊กเครื่องหมายถูกออก ตรง Create Main Class จากนั้นกดปุ่ม Finish

        3. New Java Package... และ New JFrame Form...
                3.1 คลิกขวาที่ Source Packages เลือก New--> Java Package...

                3.2  ใส่ Package Name: view จากนั้นคลิก Finish (เนื่องจากเราต้องการแยกแพกเกจออกเป็นส่วน ๆ ซึ่งส่วนนี้จะมีไว้เก็บคลาสที่เป็นหน้า UI เท่านั้น ไม่มีการทำงานใด ๆ)

                3.3 คลิกขวาที่ Package view เลือก New--> JFrame Form..

                3.4 ใส่ Class Name: UI จากนั้นกดปุ่ม Finish

        4. Design GUI  
                หลังจากเสร็จสิ้นจากขั้นตอนการ New JFrame Form แล้ว Netbeans จะสร้าง JFram มาให้ดังรูป สามาถเลือกมุมมองได้ทั้ง Source และ Design 

                 ส่วนที่หน้าต่าง Palette ก็จะมี Component มาให้สำหรับลากวางได้เลย โดยแยกเป็นหมวดหมู่ (ไม่ต้องกำหนด x, y เหมือนแต่ก่อนแล้ว ^^) แต่อย่างไรก็ตาม Component เหล่านี้ก็ยังสามารถ Customize ได้

        เรามาเริ่ม Design หน้า UI กันดีกว่า โดยบทความนี้จะสร้างเป็นโปรแกรมคิดคำนวณเกรดเฉลี่ยแบบง่าย ๆ ที่หลาย ๆ คนคงคุ้นกันเป็นอย่างดี แต่อยู่ในรูปแบบ GUI ให้ลากวางตามรูปได้เลย จากนั้นคลิกขวาเลือก Properties เพื่อกำหนดคุณสมบัติให้แต่ละ Component


                4.1 JFrame :
                        title : GPA-Demo
                        preferredSize : [287,384] (ลากให้ได้ขนาดที่ใกล้เคียง หรือตามใจชอบ)
                4.2 JLabel : 3 ตัว
                        text : จำนวน, วิชา, เกรดเฉลี่ย ตามลำดับ
                4.3 JTextField : 2 ตัว
                        jTextField1 คลิกขวาเลือก Change Variable Name ... New Name: tfSubject
                                text : ใส่ตัวเลขแล้วกด Enter
                                foreground : [153,153,153]
                                nextFocusableComponent : tfResult (กำหนดหลังจากที่ changed variable)
                        jTextField2 คลิกขวาเลือก Change Variable Name ... New Name: tfResult
                                text : 
                                enabled : false (เอาเครื่องหมายถูกออก)
                                nextFocusableComponent : btCal (กำหนดหลังจากที่ changed variable)
                4.4 JButton : คลิกขวาเลือก Change Variable Name ... New Name:btCal
                                text : คำนวณ

                4.5 JTable : 
                                ที่ Properties >> model คลิกที่ปุ่ม ... จะปรากฎไดอะล็อก model ให้กำหนดค่าต่าง ๆ ดังรูป

                *Trick เวลาที่เราลากวางนั้นจะเห็นว่าแต่ละ component จะขึ้นต่อกัน จึงทำให้บางทีจัดวางยาก แนะนำให้คลิกขวาที่ JFrame แล้วเลือก Set Layout >> Absolute Layout ทีนี้แต่ละ Component ก็จะเป็นอิสระต่อกัน เราก็สามารถไปกำหนดค่า x,y ที่ Properties ได้เช่นกัน ^^

                4.6 ทดสอบ run โปรแกรมด้วยการคลิกขวาที่ไฟล์แล้วเลือก Run File หรือกด Shift+F6 ก็จะปรากฏหน้าโปรแกรมดังรูป

        5. เขียน Code เพื่อให้โปรแกรมทำงาน 
                 5.1 เริ่มจากเขียนในส่วนของการควบคุม Component ต่าง ๆ ที่นอกเหนือจากการกำหนดใน Properties และการสร้างคลาสคำนวณเกรดเฉลี่ย โดยเริ่มจากสร้าง Package ชื่อ controller จากนั้นสร้าง จาวาคลาส 2 คลาส ชื่อว่า ControlUI.java และ Calculate.java จากนั้นเขียน Code ดังนี้

ControlUI.java        
 /*  
  * To change this template, choose Tools | Templates  
  * and open the template in the editor.  
  */  
 package controller;  
 import java.awt.Dimension;  
 import java.awt.Toolkit;  
 import javax.swing.table.DefaultTableModel;  
 /**  
  *  
  * @author T000Rxx  
  */  
 public class ControlUI {  
   int subject = 0;  
   DefaultTableModel model;  
   public ControlUI() {  
   }  
   public void setSubject(String n) {  
     subject = Integer.parseInt(n);  
   }  
   public int getSubject() {  
     return subject;  
   }  
   public void setModel(javax.swing.JTable tb) {  
     removeOldModel(tb.getRowCount());  
     model = (DefaultTableModel) tb.getModel();  
     for (int j = 0; j < getSubject(); j++) {  
       model.addRow(new Object[]{j + 1});  
     }  
   }  
   public void removeOldModel(int row) {  
     for (int i = 0; i < row; i++) {  
       model.removeRow(0);  
     }  
   }  
   public void innitComponentByDevelop(javax.swing.JFrame fm) {  
     Dimension fd = fm.getSize();  
     int w = fd.width;  
     int h = fd.height;  
     Dimension d = Toolkit.getDefaultToolkit().getScreenSize();  
     int x = (d.width - w) / 2;  
     int y = (d.height - h) / 2;  
     fm.setBounds(x, y, w, h);  
   }  
 }  

Calculate.java
 /*  
  * To change this template, choose Tools | Templates  
  * and open the template in the editor.  
  */  
 package controller;  
 import java.text.DecimalFormat;  
 import javax.swing.JTable;  
 /**  
  *  
  * @author T000Rxx  
  */  
 public class Calculate {  
   int subjectAmount = 0;  
   int listSubject[];  
   int listUnit[];  
   JTable tb;  
   double totalGrade;  
   int cumulativeCredit = 0;  
   public Calculate(javax.swing.JTable tb) {  
     this.tb = tb;  
     subjectAmount = tb.getRowCount();  
     listSubject = new int[subjectAmount];  
     listUnit = new int[subjectAmount];  
   }  
   public String calGrade() {  
     for (int i = 0; i < tb.getRowCount(); i++) {  
       cumulativeCredit+= Integer.parseInt(tb.getValueAt(i, 1).toString());  
       totalGrade+= Double.parseDouble(tb.getValueAt(i, 1).toString()) * Double.parseDouble(tb.getValueAt(i, 2).toString());  
     }  
     DecimalFormat dfm = new java.text.DecimalFormat("0.00");  
     return dfm.format(totalGrade/cumulativeCredit);  
   }  
 }  

        6. เขียน Code เพื่อกำหนด Action ของ component ต่าง ๆ ของคลาส UI
                6.1 เพิ่ม Code import ประกาศตัวแปรคลาส Control, Calculate และเพิ่ม Code ที่ Constructor ดังนี้
UI.java
package view;
import controller.Calculate; //<--Add
import controller.ControlUI; //<--Add
public class UI extends javax.swing.JFrame {
    ControlUI ct = new ControlUI(); //<--Add
    public UI() {
        initComponents();
        ct.innitComponentByDevelop(this); //<--Add
    }  
                6.2 คลิกขวาที่ Component  tfSubject[JTectField] เลือก Events->Action->actionPerformed
                6.3 เพิ่ม Code ดังนี้
 private void tfSubjectActionPerformed(java.awt.event.ActionEvent evt) {                       
   ct.setSubject(tfSubject.getText()); //<--Add  
   ct.setModel(jTable1); //<--Add  
 }  

                6.4 คลิกขวาที่ Component tfSubject[JTectField] เลือก Events->Mouse->MousePressed และเพิ่ม Code ดังนี้
 private void tfSubjectMousePressed(java.awt.event.MouseEvent evt) {  
   tfSubject.setText(""); /*<--Add*/  
   tfSubject.setFocusable(true); /*<--Add*/  
   btCal.transferFocus(); /*<--Add*/  
 }  

                6.5 คลิกขวาที่ Component btCal[JButton] เลือก Events->Action->actionPerformed และเพิ่ม Code ดังนี้ (ต้อง import controller.Calculate; ด้วย)
 private void btCalActionPerformed(java.awt.event.ActionEvent evt) {                     
   Calculate c = new Calculate(jTable1); //<--Add  
   tfResult.setText(c.calGrade()); //<--Add  
 }   

                เป็นอันว่าเสร็จสิ้น สามารถตรวจสอบ Code UI.java ทั้งหมดได้จากข้างล่างนี้
 /*  
  * UI.java  
  *  
  * Created on Dec 16, 2011, 1:45:42 PM  
  */  
 package view;  
 import controller.Calculate;  
 import controller.ControlUI;  
 /**  
  *  
  * @author T000Rxx  
  */  
 public class UI extends javax.swing.JFrame {  
   ControlUI ct = new ControlUI();  
   /** Creates new form UI */  
   public UI() {  
     initComponents();  
     ct.innitComponentByDevelop(this);  
   }  
   /** This method is called from within the constructor to  
    * initialize the form.  
    * WARNING: Do NOT modify this code. The content of this method is  
    * always regenerated by the Form Editor.  
    */  
 @SuppressWarnings("unchecked")  
 Generated Code  
 private void tfSubjectActionPerformed(java.awt.event.ActionEvent evt) {                       
   ct.setSubject(tfSubject.getText());  
   ct.setModel(jTable1);  
 }                       
 private void tfSubjectMousePressed(java.awt.event.MouseEvent evt) {                      
   tfSubject.setText("");  
   tfSubject.setFocusable(true);  
   btCal.transferFocus();  
 }                     
 private void btCalActionPerformed(java.awt.event.ActionEvent evt) {                     
   Calculate c = new Calculate(jTable1);  
   tfResult.setText(c.calGrade());  
 }  
 /**  
    * @param args the command line arguments  
    */  
   public static void main(String args[]) {  
     /* Set the Nimbus look and feel */  
      Look and feel setting code (optional)  
 /* Create and display the form */  
     java.awt.EventQueue.invokeLater(new Runnable() {  
       public void run() {  
         new UI().setVisible(true);  
       }  
     });  
   }  
   // Variables declaration - do not modify  
   private javax.swing.JButton btCal;  
   private javax.swing.JLabel jLabel1;  
   private javax.swing.JLabel jLabel2;  
   private javax.swing.JLabel jLabel3;  
   private javax.swing.JScrollPane jScrollPane1;  
   private javax.swing.JTable jTable1;  
   private javax.swing.JTextField tfResult;  
   private javax.swing.JTextField tfSubject;  
   private org.jdesktop.beansbinding.BindingGroup bindingGroup;  
   // End of variables declaration  
 }  

        ทดสอบรันโปรแกรม 
1. ใส่จำนวนวิชา แล้วกด Enter จากนั้น โปรแกรมจะไปสร้าง Model ของ Table ให้ออกมาตามจำนวนวิชาที่กรอกเข้าไป
2. ใส่หน่วยกิตของแต่ละวิชา
3. ใส่เกรดของแต่ละวิชา
4. กดปุ่มคำนวณ

         เป็นอย่างไรกันบ้างครับสำหรับบทความนี้ ก็เป็นโปรแกรมง่าย  ๆ ซึ่งผมไม่ขออธิบายในส่วนของ Code ซึ่งผมใช้วิธีการเขียนแบบแยกกันเป็นส่วน ๆ คล้ายลักษณะ MVC ซึ่งส่วนของ Control ก็จะทำหน้าที่ควบคุมการทำงานต่าง ๆ เช่น Method ต่าง ๆ ที่ใช้คำนวณ Method ที่ใช้ควบคุมการทำงานของ Component ในส่วนของ View ก็จะเป็นแค่หน้า UI และ Action ต่าง ๆ ของ Component เท่านั้น ซึ่งก็จะทำให้ง่ายต่อการ Develop ในกรณีที่เขียนเป็นโปรแกรมที่ใหญ่กว่านี้

3 ความคิดเห็น: