Posts Tagged ‘http://inhuaschool.com/index.php?option=com_content&view=article&id=12%3Aaplikasi-kalkulator-sederhana-dengan-gft&catid=9%3Ajava&Itemid=5&limitstart=5’

Aplikasi Kalkulator Sederhana dengan GFT

0, January 29, 2011
Posted by ikisuke

Artikel berikut ini merupakan contoh penerapan framework GFT untuk membuat aplikasi kalkulator sederhana.  Pembuatan aplikasi kalkulator ini dilakukan dengan menulis kode program secara manual (on the scratch) tidak memanfaatkan drag-drop komponen dari pallete swing.  Tujuan yang diharapkan adalah kode akan lebih rapi dan pemahaman terhadap kerja java akan lebih baik.

Penerapan disiplin framework GFT (Grammatical Fast Track) memberikan tahapan-tahapan dalam membangun aplikasi software sebagai berikut:

  1. Memisahkan fungsi engine aplikasi dan presentasi (dalam hal ini perlu dibuat Logik kalkulator dan GUI Kalkulator scr terpisah)
  2. Lakukan analisa terhadap fungsi kerja kalkulator dari sisi fungsi operasional selanjutnya desain class logik kalkulator
  3. Desain Class CalcLogic sebagai engine kalkulator
  4. Test unit CalcLogic sehingga memenuhi fungsi sebagai kalkulator
  5. Desain mock up presentasi kalkulator (swing) tersendiri (Class CalcGUI)
  6. Bagian yang tersulit Interaksi dinamis antara Mock Up ClacGUI dengan logik kalkulator CalcLogic

Memisahkan Engine dan presentasi pada kalkulator
Pada tahap ini merupakan observasi terhadap fungsi kalkulator.  Ingat tanpa kalkulator sebenarnya kita juga bisa menghitung.  Hal ini berarti kita sendiripun mempunyai engine kalkulator.   Perhatikan Gambar di bawah, pada awalnya _currentTotal = 0.  Setiap operasi hitung (+,-,*,/,=) mempunyai satu operand yang akan dioperasikan dengan _currentTotal sebelumnya.

01./*
02. * Silahkan didistribusikan
03. * Mudah-mudahan bermanfaat
04. */
05.
06./*
07. * @author nurudin at Inhuaschool akademic
09. */
10.//Class CalcLogic murni engine kalkulator dan tidak boleh ada komponen Window (UI)
11.public class CalcLogic {
12. private int _currentTotal;
13. public CalcLogic () {
14. _currentTotal =0;
15. }
16. public void tambah (String n) {
17. _currentTotal += convertToNumber(n);
18. }
19. public void kurang (String n) {
20. _currentTotal -= convertToNumber(n);
21. }
22. public void kali (String n) {
23. _currentTotal *= convertToNumber(n);
24. }
25. public void bagi (String n) {
26. _currentTotal /= convertToNumber(n);
27. }
28. public int convertToNumber (String n) {
29. return Integer.parseInt(n);
30. }
31. public void setTotal (String n) {
32. _currentTotal = convertToNumber(n);
33. }
34. public String getTotalString () {
35. return "" + _currentTotal;
36. }
37.}

Langkah selanjutnya adalah menguji fungsi class CalcLogic tersebut menggunakan Unit Test.

Tes Unit Business Logic Kalkulator

Metode GFT memberikan pemahaman bahwa UI kalkulator tidak boleh dibuat sebelum Unit Test pada aplikasi kalkulator sudah dilakukan dan dinyatakan jalan.  Berikut ini adalah test unit sederhana yang digunanakan untuk menguji fungsi kalkulator sebagai engine aplikasi.  Catatan pada unit test tidak boleh terdapat komponen swing (UI), hanya untuk memastikan bahwa engine harus benar-benar terpisah dari presentasi.

Unit Test Class CalcLogic (engine kalkulator)

/*
 * Silahkan didistribusikan
 * Mudah-mudahan bermanfaat
 */

/*
 * @author nurudin at Inhuaschool akademic
 * http://inhuaschool.com
 */
public class TestUnitCalcLogic {
    public static void main (String args[]){
        System.out.println("Test Kalkulasi berikut : 4+6-2/2=");
        CalcLogic kalkulator = new CalcLogic();
        //4 adalah angka awal dan saat ini _currentTOtal adalah 0
        System.out.println("_currentTotal adalah ="+kalkulator.getTotalString());
        //klik operator tambah (+)
        kalkulator.tambah("4");
        System.out.println("_currentTotal adalah ="+kalkulator.getTotalString());
        //operand 6
        //klik operator kurang
        kalkulator.tambah("6");
        System.out.println("_currentTotal adalah ="+kalkulator.getTotalString());
        //operand 2
        //klik operator kurang
        kalkulator.kurang("2");
        System.out.println("_currentTotal adalah ="+kalkulator.getTotalString());
        //operand 2
        //klik operator kurang
        kalkulator.bagi("2");
        System.out.println("_currentTotal adalah ="+kalkulator.getTotalString());
        //klik sama dengan
        kalkulator.setTotal(kalkulator.getTotalString());
        System.out.println("TOTAL = "+kalkulator.getTotalString());
    }
}

Hasil pengujian unit engine kalkulator sebagai berikut:

run:
Test Kalkulasi berikut : 4+6-2/2=
_currentTotal adalah =0
_currentTotal adalah =4
_currentTotal adalah =10
_currentTotal adalah =8
_currentTotal adalah =4
TOTAL = 4
BUILD SUCCESSFUL (total time: 1 second)

Perhatikan bahwa proses kalkulator seperti interpreter pada program.  Setelah teruji berfungsi semua operasi baik (+,-,*,/,=) maka proses selanjutnya adalah membuat mock up presentasi kalkulator.  Mock up kalkulator ini belum berfungsi sebagai kalkulator.  Dengan pemisahan engine kalkulator tersebut maka aplikasi kalkulator akan terlepas dari presentasi jenis apapun baik desktop (swing) atau web.

Mock Up Kalkulator (swing on the scratch)

Beberapa pertimbangan mengapa pada tutorial ini menggunakan on the scratch adalah kode program lebih rapi, lebih mengerti java (memahami MVC dan konsep event) dan lebih terasa membuat program sendiri Wink.  OK Untuk membuat aplikasi swing dengan cara jadul on the scratch (jos) maka mutlak harus memahami Layout Manager dari java SE.  Silahkan baca-baca referensi berikut Layout Manager swing.

Pada akhir baca referensi tersebut terdapat beberapa layout pada swing (BorderLayout, FlowLayout, BoxLayout, CardLayout, GridLayout).  Desain mock up menggunakan swing mutlak harus memahami penggunaan Layout-layout tersebut jika ingin tampilannya seperti yang diharapkan.
Layout mock up kalkulator

Pada gambar di samping terlihat bahwa pada main layout kalkulator seharusnya menggunakan BorderLayout.  Sedangkan panel-panel yang lain sebagai isi dari main panel adalah 2 panel menggunakan layout GridLayout (grup nomer dan grup operator) dan 2 lainya (display Field dan Clear) menggunakan FlowLayout.

Variable
Keterangan Layout
mainPanel Panel Utama BorderLayout
numberPanel Panel group number GridLayout
opPanel Panel grup Operator GridLayout
displayPanel display kalkulator FlowLayout
clearPanel tombol clear display FlowLayout

Bisa diperkirakan sekarang tata letak masing-masing panel tersebut.  Aplikasi kalkulator harus mewarisi swing.javax.JFrame.  Panel utama mainPanel akan menempel pada JFrame, sedangkan panel yang lainnya merupakan isi dari mainPanel.

Dari gambar di samping dapat dilihat di mana letak masing-masing panel dalam mainPanel. numberPanel di CENTER, displayPanel di NORTH, opPanel di EAST, dan clearPanel di SOUTH.  Hal ini dapat dinyatakan dalam script berikut.  Coba buat dengan cara jos (jadul on the scratch) biar lebih memahami kerja java.  Kelas CalculatorGUI berikut ini merupakan kerangka panel seperti yang telah dijelaskan di atas.

class CalculatorGUI extends JFrame{
public static void main  (String args[]){
 // letak create object CalculatorGUI dan menjalankan aplikasi kalkulator
CalculatorGUI calcGUI = new CalculatorGUI();
calcGUI.setVisible(true);
}
 //constructor
 public CalculatorGUI(){

/*
1. buat panel display
 2. buat panel Number
3. buat panel Operator
 4. buat panel Clear
 5. buat panel Utama mainPanel
 letakkan panel 1-4 ke panel 5 mainPanel

 Selanjutnya Panel utama letakkan pada JFrame CalculatorGUI*/
 }
}

Eksekusi kode program di atas hanya menampilkan window JFrame saja karena constructor CalculatorGUI belum diberikan komponen-komponen.

/*
 * Silahkan didistribusikan
 * Mudah-mudahan bermanfaat
 */

/*
 * @author nurudin at Inhuaschool akademic
 * http://inhuaschool.com
 */
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.BorderFactory; 
import javax.swing.JButton; 
import javax.swing.JTextField; 

public class CalculatorGUI extends JFrame{ 
    //referensi komponen selama operasi 
    private static final Font BIGGER_FONT = new Font("monspaced", Font.PLAIN, 20); 
    private JTextField _displayField; 
    boolean _startNumber = true;
    private String _previousOp = "="; 
public static void main(String args []){          
        try { 
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
        }catch (Exception unUsed){};         
        CalculatorGUI calGui = new CalculatorGUI(); 
        calGui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        calGui.setVisible(true); 
    }
//<strong>constructor -- draw mock up here</strong>
public CalculatorGUI(){

         //<strong>1. Buat Panel Display</strong> -Display Field --> karena cuma 1 komponen JTextField saja bisa dibuat tanpa panel 
         _displayField = new JTextField(); 
         _displayField.setHorizontalAlignment(JTextField.RIGHT); 
         _displayField.setFont(BIGGER_FONT); 

       //<strong>2. Buat Panel Number </strong>
         String buttonOrder = "789456123 0 "; 
         JPanel numberPanel = new JPanel(); 
         numberPanel.setLayout(new GridLayout(5, 3, 2, 2));
      //Registrasi komponen swing ke object listener  
         for (int i=0;i < buttonOrder.length();i++){ 
             String keyTop = buttonOrder.substring(i, i+1); 
             JButton b = new JButton(keyTop); 
             if (keyTop.equals(" ")){ 
                 b.setEnabled(false); 
             } else { 
             b.setFont(BIGGER_FONT); 
             //Registrasi object listener pada component 
             } 
             buttonPanel.add(b); 
         } 

       //<strong>3. Buat Panel Operator</strong> 
         JPanel opPanel = new JPanel(); 
         opPanel.setLayout(new GridLayout(5, 1, 2, 2));
       //Tempat instan object OperatorListener
         String [] opOrder = {"+","-","*","/","="}; 
         for (int i=0; i
             JButton b = new JButton(opOrder[i]); 
             b.setFont(BIGGER_FONT); 
          //Registrasi komponen swing ke object listener             
       opPanel.add(b); 
         }  

        //<strong>4. Buat clear panel </strong>
         JPanel clearPanel = new JPanel(); 
         clearPanel.setLayout(new FlowLayout()); 
         JButton clearButton = new JButton("CLEAR"); 
         clearButton.setFont(BIGGER_FONT); 
         //Registrasi komponen swing ke object listener --> karena cuma 1 object boleh langsung dibuatkan obejct listenernya
         clearPanel.add(clearButton);

        //<strong>5. Buat main Panel</strong> 
        //put all panel together into mainPanel
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BorderLayout(5, 5)); 
        mainPanel.add(_displayField,BorderLayout.NORTH); 
        mainPanel.add(buttonPanel, BorderLayout.CENTER);         
        mainPanel.add(opPanel, BorderLayout.EAST);
         mainPanel.add(clearPanel,BorderLayout.SOUTH); 
        mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 

        //<strong>6. Meletakkan mainPanel pada JFrame</strong>
        //Draw
        this.setContentPane(mainPanel); 
        this.setLocationRelativeTo(null); 
        this.pack(); 
        this.setResizable(false); 
        this.setTitle("KALKULATOR");
}
}

Mulai bingung kan? pelan-pela. Menulis program harus tau alurnya.  Jangan di tulis dari atas ke bawah.  Buat secara bertahap dan coba jalankan.  Mulai lah dari container dulu, untuk contoh script di atas Anda dapat memulai dari tampilan frame dulu kemudian No. 6 buat main Panel dulu sebelum panel yg lain karena mainPanel adalah container dari panel panel yang lainnya.  Selanjutnya mulai dari No. 1 buat display Panel kemudian tambahkan ke mainPanel dan lihat hasilnya. Dan seterusnya.  Dengan demikian maka tahapan kemajuan akan lebih terlihat dan kesalahanpun lebih mudah diketahui.

Perlu diingat bahwa Mock Up adalah presentasi tanpa ada proses. Sampai pada tahap ini Anda mestinya bisa melihat bagaimana keuntungan yang diperoleh dengan memisahkan bagian Logik bisnis dan bagian presentasi.  Hal ini menjadi fitur utama proses framework GFT.  Pemisahan ini akan memudahkan dalam teamwork proses develop suatu software dimana desainer tampilan akan bekerja sendiri tanpa harus mengganggu programmer engine.

Siap ke bagian yang lebih sulit? hehe yang nulispun agak kesulitan mengungkapkan tutorial agar mudah dipahami. minum dulu.

Komunikasi dan Interaksi CalculatorGUI dan CalcLogic
Pada bagian ini akan diuraikan bagaimana interaksi event-driven pada komponen-komponen swing dan penerapan inner class untuk Listener setiap object swing.  Bagian interaksi ini cukup rumit untuk dijelaskan.

Baiklah kita mulai dari Peran masing-masing yang berinteraksi.  Konsep GFT memberikan aturan bagaimana interaksi antar 2 buah object atau lebih.  Perhatikan bahwa agar fungsi aplikasi kalkulator tersebut lengkap maka interaksi antara object CalculatorGUI dan object CalcLogic harus dinamis dan jelas.

Relasi secara grammatical (sisi analisa bahasa dari GFT) kedua class tersebut adalah:
CalculatorGUI mempunyai CalcLogic
Arti relasi tersebut adalah agar fungsi kalkulator dapat terwujud maka class CalculatorGUI harus mempunyai data referensi class CalcLogic.  Atau dengan kata lain object CalculatorGUI akan berfungsi sebagai kalkulator jika mempunyai object CalcLogic untuk menjalankan fungsi-fungsi perhitungan.

Nah dari analisa grammatical tersebut maka dapat disimpulkan beberapa peran penting masing masing object tersebut dalam interaksinya, yaitu:

  • Object CalculatorGUI sebagai direktur atau commander object ini tidak boleh kerja tapi hanya memberikan order (direktur hanya menyuruh akuntan untuk menghitung)
  • Object CalcLogic adalah pekerja dalam hal ini dia hanya bertugas menerima order dari sang direktur dan memberikan hasil perhitungannya

Konsep analisa ini akan memudahkan dalam memahami interaksi 2 object tersebut untuk membangun aplikasi kalkulator.  Ya begini lah seharusnya belajar OOP semua bisa dianalogikan seperti kehidupan sehari-hari.  Tabel interaksi yang terjadi pada kalkulator.  Amati kembali mock up kalkulator di atas.  Berikut adalah tabel interaksi yang terjadi:

No. mock up (sang direktur) Tugas, Interaksi Keterangan analogi
1. Constructor Creator object CalcLogic rekruit akuntan
2. displayField pasif Hanya menampilkan hasil
3. numberPanel Order to displayField perlu Listener (numberListener)
4. opPanel Order to object CalcLogic perlu Listener untuk memproses hitungan (opListener)
5. clearPanel Order to displayField perlu Listener inisialisasi proses hitungan (clearListener)
  • Setiap ada order maka membutuhkan Listener.

Perhatikan tabel di atas bahwa dari keempat object dalam mock up kalkulator tersebut (displayField, numberPanel, opPanel, dan clearPanel) hanya opPanel saja yang berinteraksi dengan engine (object CalcLogic).  Sedangkan object yang lainnya hanya berinteraksi di dalam bagian dari presentasi mock up kalkulator saja.

Ada 5 pekerjaan yang perlu ditambahkan pada mock up kalkulator agar dapat berinteraksi masing-masing komponen ataupun berinteraksi dengan object CalcLogic.  Pahami mengapa butuh 5 macam tugas tersebut untuk menghidupkan fungsi kalkulator pada mock up.  Baik kita uraikan satu-satu tugas tersebut:

1. Bagian Constructor
Ingat relasi antar object CalculatorGUI dan object CalcLogic (CalculatorGUI mempunyai CalcLogic) sehingga:
Tambahkan private CalcLogic kalkulator = new CalcLogic(); pada data class CalculatorGUI.  Kode ini berarti bahwa begitu instan object CalculatorGUI maka secara otomatis mempunyai data bertipe CalcLogic yaitu kalkulator (yang merupakan pointer object CalcLogic).

2. displayField
displayField hanya menampilkan angka operand maupun hasil perhitungan saja.  Silahkan disesuaikan dengan keinginan properti dari tampilan display tersebut.  Pada script di atas tampilan angka diperbesar dan dibuat rata kanan.

3.4.5. Urusan Listener
What is Listener exactly?  Pertanyaan yang mendasar.  referensi berikut tentu sangat membantu http://java.sun.com/docs/books/tutorial/uiswing/events/index.html. Listener adalah suatu interface yang disediakan oleh java untuk memonitor dan menangkap event dari object-object (swing component).

Gambar di bawah ini menunjukkan bagaimana mekanisme komunikasi antara object komponen swing dengan object Listener.
event listener
event source dibangkitkan oleh object komponen swing, kemudian ditangkap oleh object listener.  Ingat klik move, drag, double click semua adalah event.  Pada API java jenis dari event listener sangat banyak sekali masing-masing disesuaikan dengan kegunaannya. misal operasi event berkaitan dengan window adalah Window Listener sedangkan yang berkaintan dengan event mouse adalah Mouse Listener.

OK. event listener mana yang kita butuhkan untuk aplikasi kalkulator.  Action Listener adalah listener yang umum digunakan berkaitan dengan operasi yang diinginkan dari komponen swing.  Pada object Action Listener ini order dan action interaksi kalkulator diberikan.  Sehingga pada aplikasi di atas dibutuhkan 3 buah Action Listener (anggap masing-masing panel membutuhkan listener tersendiri, biar modular).

Bagaimana mekanisme kerja Action Listener?  Terdapat 3 tahap yang harus diberikan yaitu:

  1. Mendeklarasikan class yang mengimplementasi ActionListener
    pubic class NumberListener implements ActionListener
  2. implement kode pada method actionPerformed
    public void actionPerformed(ActionEvent ev){
    //kode ditulis disini
    }
  3. Mendaftarkan objectActionListener pada object komponen swing
    buttonNumber.addActionListener(new NumberListener());

Sekarang buat class-class NumberListener, OperatorListener, dan ClearListener sebagai class dari object listener yang akan melayani event dari masing-masing panel terkait.

Buat NumberListener, OperatorListener, ClearListener

Secara grammatical NumberListene, OperatorListener, dan ClearListener harus merupakan Action Listener.  Oleh sebab itu ketiga class tersebut harus mengimplementasikan interface ActionListener.  Sehingga ketiganya adalah ActionListener.  Dan ingat bahwa class yang mengimplementasikan suatu interface harus mengimplementasikan semua method-methodnya.

Penerapan pada NumberListener untuk menangani event dan action dari object di dalam panelNumber:

    class NumberListener implements ActionListener{ 
        public void actionPerformed (ActionEvent e){ 
            String digit = e.getActionCommand(); 
            if (_startNumber){            
            _displayField.setText(digit); 
            _startNumber = false; 
            } else 
            { 
            _displayField.setText(_displayField.getText()+digit); 
            } 
        } 
    }

Interaksi antara button-button nomer yang ada pada numberPanel dengan display Panel ditunjukkan pada kode program di dalam method actionPerformed di atas.  boolead _startNumber digunakan untuk membedakan apakah nomer awal atau nomer kedua dst.

Penerapan pada OpListener untuk menangani event dan action dari object di dalam panelOperator:

    class OpListener implements ActionListener { 
        public void actionPerformed (ActionEvent e){ 
            if (_startNumber){ 
                actionClear(); 
                _displayField.setText("ERROR OPERATOR"); 
            }else { 
                _startNumber = true; 
               try { 
                   String displayText = _displayField.getText(); 
                   if (_previousOp.equals("=")){ 
                       kalkulator.setTotal(displayText); 
                   } else if (_previousOp.equals("+")) { 
                       kalkulator.tambah(displayText); 
                   } else if (_previousOp.equals("-")) { 
                       kalkulator.kurang(displayText); 
                   } else if (_previousOp.equals("*")) { 
                       kalkulator.kali(displayText); 
                   } else if (_previousOp.equals("/")) { 
                       kalkulator.bagi(displayText); 
                   }  
                   _displayField.setText(""+kalkulator.getTotalString()); 
               }  
                catch (NumberFormatException ex) 
                { 
                   actionClear(); 
                   _displayField.setText("Error"); 
                } 
                _previousOp = e.getActionCommand(); 
}
}
}

Perhatikan komunikasi order dari button operator kepada object kalkulator sebagai instant dari class CaclLogic.  Pada script tersebut terlihat bahwa pada presentasi kalkulator tidak terdapat proses perhitungan bagi +,-,*atau/ akan tetapi mendelegasikan tugas tersebut kepada object CaclLogic sebagai engine perhitungan kalkulator.

Class ClearListener menangani event dan action dari object di dalam clearPanel:

//inisialisasi kalkulator    
private void actionClear(){ 
        _displayField.setText("0"); 
        _startNumber = true; 
        _previousOp = "="; 
        kalkulator.setTotal("0"); 
    } 

    class ClearListener implements ActionListener { 
        public void actionPerformed(ActionEvent e) { 
            actionClear(); 
        } 
    }

Method actionClear terletak di dalam class CalculatorGUI dan class ClearListener memanggil method tersebut.  Artinya agar class ClearListener dapat melihat method actionClear maka class ClearListener dijadikan sebagai inner class dari CalculatorGUI.  Begitu juga dengan class listener lainnya.

Penggunaan ActionListener pada kalkulator

Apa fungsi suatu listener pada aplikasi kalkulator ini? listener adalah suatu object yang khusus menangani event dan action dari aplikasi berbasis swing.  Listener berfungsi sebagai Controller (dalam MVC) dan suatu proxi atau controller juga pada pattern GOF (Gang of Four).  Listener ini bertugas untuk memetakan semua operasi (action) pada aplikasi swing.  Lalu bagaimana object listener dapat mengerti request dari komponen swing?  object komponen swing harus diregistrasikan dulu pada object listener.  Cara meregistrasikan komponen swing pada listener:

buttonNumber.addActionListener(new NumberListener());

Object NumberListener akan memonitor semua event dan menjalankan action yang diperlukan oleh buttonNumber.  Nah sekarang kembali ke script CalculatorGUI, perhatikan comment yang saya berikan //Registrasi komponen swing ke object listener.  Di situ tempat Anda harus meregistrasikan komponen swing pada listener.

Finishing & Snapshop Kalkulator

Perlu diperhatikan bahwa penggunaan inner class dapat diinsta secara langsung oleh outer class (class induknya).  Mengapa dibutuhkan inner class (NumberListener, OpListener, dan clearListener) bisa kah dibuat class tersendiri?  Di buat class tersendiri bisa, yang jadi pertimbangan dijadikan inner class hanyalah modular sj karena fungsi tersebut hanya untuk kalkulator maka di ringkas dalam innner class CalculatorGUI.

Berikut snapshot yang barusan saya jalankan :

Snapshot Kalkulator

Selamat mencoba, script ada di bagian atas artikel ini. mungkin ada beberapa istilah variabel yang berbeda dengan tulisan ini, silahkan disesuaikan.  Terima kasih.