Monday, December 19, 2016

Bab 3. Java Struktur Data dan Pemrograman GUI



Bab.3 Pemrograman Event-Driven

Tujuan Instruksional
·         Menjelaskan event, sumber event, dan kelas-kelas event.
·         Mendefinisikan kelas listener, objek listener register dengan objek sumber.
·         Mendefinisikan kelas listener menggunakan kelas inner (kelas sebelah dalam).
·         Mendefinisikan kelas listener menggunakan kelass inner tak-bernama.
·         Mengeksplorasi berbagai gaya pengkodean untuk menciptakan dan meregistrasi listener.

·         Mendapatkan masukan dari bidang teks setelah penekanan tombol.
·         Menulis program untuk menangani WindowEvent.
·         Menyederhanakan pengkodean untuk kelas listener menggunakan adapter antarmuka listener.
·         Menulis program untuk menangani MouseEvent.
·         Menulis program untuk menangani KeyEvent.
·         Menggunakan kelas javax.swing.Timer untuk mengendalikan animasi.

3.1 Introduksi

Dimisalkan Anda ingin menulis suatu program GUI yang mengijinkan pengguna untuk memasukkan jumlah hutang, suku bunga tahunan, dan jumlah tahun pinjaman dan menekan tombol Hitung Hutang untuk mendapatkan pembayaran bulanan dan total pembayaran, seperti ditunjukkan pada Gambar 3.1a. Bagaimanakah Anda menyelesaikan masalah tersebut? Anda harus menggunakan pemrograman event-driven untuk menulis kode yang merespon event penekanan-tombol.


Gambar 3.1 Program  menghitung pembayaran hutang

Dimisalkan pula Anda ingin menulis suatu program untuk menganimasi suatu bendera yang sedang berkibar. Bagaimana Anda mengatasi hal ini? Ada beberapa cara mengatasi hal ini. Salah satu cara yang efektif adalah menggunakan timer atau pewaktu dalam pemrograman event-driven, yang merupakan subjek pembahasan dalam bab ini.
Di dalam pemrograman event-driven, kode dieksekusi ketika suatu event terjadi (misalnya oleh pengklikan tombol, oleh pergerakan mouse, atau oleh timer).

3.2 Event dan Sumber Event
Ketika Anda menjalankan suatu program GUI JAVA, program berinteraksi dengan pengguna, dan event menyetir arah eksekusi. Event didefinisikan sebagai suatu sinyal kepada program bahwa sesuatu telah terjadi. Event dipicu oleh aksi pengguna eksternal, seperti pergerakan mouse, pengklikan tombol, dan penekanan papan-kunci, atau oleh aktivitas program internal, seperti timer. Program dapat memilih untuk merespon atau mengabaikan event yang terjadi.

Komponen yang menciptakan suatu event dan memicunya disebut dengan objek sumber atau komponen sumber. Sebagai contoh, suatu tombol adalah objek sumber untuk event pengklikan-tombol. Event merupakan instans dari suatu kelas event. Kelas akar dari kelas-kelas event adalah java.util.EventObject. Relasi hirarhki atas beberapa kelas event ditampilkan pada Gambar 3.2.


Gambar 3.2 Event adalah suatu objek dari kelas EventObject

Objek event memuat properti-properti yang melekat pada event terkait. Anda dapat mengidentifikasi objek sumber dari suatu event menggunakan metode instans getSource() di dalam kelas EventObject. Sub-subkelas dari EventObject digunakan untuk menangani tipe-tipe event tertentu, seperti event aksi, event jendela, event komponen, event mouse, dan event kunci. Tabel 3.1 menyimpulkan aksi pengguna eksternal, objek sumber, dan tipe event yang dipicu.


3.3 Listener, Registrasi, dan Penanganan Event
JAVA menggunakan model berbasis delegasi dalam menangani event: Suatu objek sumber memicu event, dan suatu objek menangani event tersebut. Objek yang terakhir ini disebut dengan listener. Agar suatu objek dapat menjadi listener untuk event yang dipicu oleh objek sumber, dua hal diperlukan, seperti ditampilkan pada Gambar 2.3.


Tabel 3.1 Aksi Pengguna, Objek Sumber, dan Tipe Event

Aksi Pengguna
Objek Sumber
Tipe Event
Pengklikan suatu tombol

Hasil pengisian pada bidang teks

Pemilihan suatu item baru

Pemilihan item

Pengklikan suatu kotak periksa

Pengklikan suatu kotak radio

Memilih suatu item menu

Menggerakkan batang penggeser (scroll bar)

Menggerakkan batang penggeser (scroll bar)

Jendela dibuka, ditutup, dll

Mouse ditekan, dilepas, dll

Menggeser atau menggeret (drag) mouse

Melepas atau menekan kunci pada papan-ketik.

Komponen ditambahkan atau dihapus dari kontainer

Komponen digeser, diubah ukurannya, disembunyikan, atau ditampilkan

Komponen dikaburkan atau difokuskan


JButton

JTextField


JComboBox

JList

JCheckBox


JRadioButton


JMenuItem

JScrollBar


JSlider


Window


Component

Component


Component


Container


Component



Component
ActionEvent

ActionEvent


ItemEvent, ActionEvent

ListSelectionEvent

ItemEvent, ActionEvent


ItemEvent, ActionEvent


ActionEvent

AdjustmentEvent


ChangeEvent


WindowEvent


MouseEvent

MouseEvent


KeyEvent


ContainerEvent


ComponentEvent



FocusEvent


1.  Objek listener harus merupakan instans dari antarmuka event-listener untuk memastikan bahwa listener memiliki metode yang tepat dalam memproses event. JAVA menyediakan suatu antarmuka listener untuk setiap jenis event. Antarmuka listener biasanya dinamai XListener untuk XEvent, dengan eksepsi MouseMotionListener. Sebagai contoh, antarmuka listener untuk ActionEvent adalah ActionListener; Setiap listener untuk ActionEvent harus mengimplementasikan antarmuka ActionListener. Tabel 3.2 mencantumkan jenis-jenis event, antarmuka listener, metode-metode yang didefinisikan di dalam antarmuka listener.
2.  Objek listener harus diregistrasi oleh objek sumber. Metode-metode registrasi bergantung pada tipe event. Untuk ActionEvent, metodenya adalah addActionListener. Pada umumnya, metode dinamakan addXListener untuk XEvent. Suatu objek sumber dapat memicu beberapa tipe event. Objek sumber menetapkan daftar listener terregistrasi dan memberitahukan kepada listener dengan cara memanggil handler dari objek listener untuk merespon event, seperti tertampil pada Gambar 3.4. (Gambar 3.4 menampilkan implementasi internal dari suatu kelas sumber. Untuk menggunakannya, Anda tidak perlu mengetahui bagaimana suatu kelas sumber, seperti JButton, diimplementasikan. Akan tetapi, dengan mengetahui implementasi kelas, Anda akan lebih mengerti pemrograman event-drivent JAVA).



Gambar 3.3 Listener merupakan instans dari antarmuka listener dan harus diregistrasi dengan suatu komponen sumber


Diinginkan untuk merevisi kode1.8, PenangananEvent.java. Karena objek JButton memicu ActionEvent, suatu objek listener untuk ActionEvent harus berupa instans dari ActionListener, sehingga kelas listener mengimplementasikan ActionListener pada baris 34. Objek sumber memanggil addActionListener(listener) untuk meregistrasi suatu listener, sebagai berikut:  

JButton jbtOK = new JButton("OK"); // Baris 7 dalam kode14.8
ActionListener listener1
  = new OKListenerClass();  // Baris 18 dalam kode14.8
jbtOK.addActionListener(listener1); // Baris 20 dalam kode14.8

Ketika Anda mengklik suatu tombol, objek JButton memicu suatu ActionEvent dan melewatkannya untuk memanggil metode actionPerformed dari listener untuk menangani event.

Tabel 3.2 Event, Event Listener, dan Metode Listener

Kelas Event (Handler)
Antarmuka Listener
Metode Listener
ActionEvent

ItemEvent

MouseEvent









KeyEvent




WindowEvent







ContainerEvent


ComponentEvent




FocusEvent



AdjustmentEvent

ChangeEvent

ListSelectionEvent

ActionListener

ItemListener

MouseListener





MouseMotionListener


KeyListener



WindowListener







ContainerListener


ComponentListener




FocusListener


AdjustmentListener

ChangeListener

ListSelectionListener

actionPerformed(ActionEvent)

itemStateChanged(ItemEvent)

mousePressed(MouseEvent)
mouseReleased(MouseEvent)
mouseEntered(MouseEvent)
mouseExited(MouseEvent)
mouseClicked(MouseEvent)

mouseDragged(MouseEvent)
mouseMoved(MouseEvent)

keyPressed(KeyEvent)
keyReleased(KeyEvent)
keyTyped(KeyEvent)

windowClosing(WindowEvent)
windowOpened(WindowEvent)
windowIconified(WindowEvent)
windowDeiconified(WindowEvent)
windowClosed(WindowEvent)
windowActivated(WindowEvent)
windowDeactivated(WindowEvent)

componentAdded(ContainerEvent)
componentRemoved(ContainerEvent)

componentMoved(ComponentEvent)
componentHidden(ComponentEvent)
componentResized(ComponentEvent)
componentShown(ComponentEvent)

focusGained(FocusEvent)
focusLost(FocusEvent)

adjustmentValueChanged(AdjustmentEvent)

stateChanged(ChangeEvent)

valueChanged(ListSelectionEvent)


Objek event memuat informasi yang terkait dengan event tersebut, yang dapat diperoleh menggunakan metode-metode, seperti tertampil pada Gambar 3.5. Misalnya, Anda dapat menggunakan metode e.getSource() untuk memperoleh objek sumber agar dapat menentukan apakah objek sumber tersebut adalah tombol, kotak periksa, atau kotak radio. Untuk suatu event aksi, Anda dapat menggunakan e.getWhen() untuk memperoleh waktu ketika event terjadi.


Gambar 3.4 Objek sumber memberitahukan listener event terkait dengan memanggil handler dari objek listener tersebut.



Gambar 3.5 Anda dapat menggunakan informasi berguna dari suatu objek event


Sekarang Anda dapat menulis suatu program yang menggunakan dua tombol untuk mengendalikan ukuran suatu lingkaran, seperti ditunjukkan pada Gambar 3.6. Program ini akan dikembangkan secara bertahap. Pertama, akan ditulis program pada kode3.1 yang menampilkan antarmuka pengguna dengan suatu lingkaran di tengah (baris 14) dan dua tombol di bawah (baris 15).

Kode3.1 KendaliLingkaran1.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import javax.swing.*;
import java.awt.*;

public class KendaliLingkaran1 extends JFrame {
  private JButton jbtPerbesar = new JButton("Perbesar");
  private JButton jbtPerkecil = new JButton("Perkecil");
  private PanelLingkaran kanvas = new PanelLingkaran();

  public KendaliLingkaran1() {
    JPanel panel = new JPanel(); // Menggunakan panel untuk mengelompokkan tombol
    panel.add(jbtPerbesar);
    panel.add(jbtPerkecil);

    this.add(kanvas, BorderLayout.CENTER); // Menambah kanvas ke tengah
    this.add(panel, BorderLayout.SOUTH); // Menambahkan tombol ke frame
  }

  /** Metode utama */
  public static void main(String[] args) {
    JFrame frame = new KendaliLingkaran1();
    frame.setTitle("KendaliLingkaran1");
    frame.setLocationRelativeTo(null); // Pusat frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(200, 200);
    frame.setVisible(true);
  }
}

class PanelLingkaran extends JPanel {
  private int radius = 5; // Radius lingkaran default

  /** Menggambar lingkaran */
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.drawOval(getWidth() / 2 - radius, getHeight() / 2 - radius,
     2 * radius, 2 * radius);
  }
}


Bagaimana Anda memperbesar atau memperkecil lingkaran? Ketika tombol Perbesar diklik, Anda menginginkan lingkaran tersebut digambarkan dengan radius yang lebih besar. Bagaimana Anda melakukannya? Anda dapat mengembangkan program pada kode3.1 menjadi kode3.2 dengan fitur-fitur tambahan sebagai berikut:
1.  Mendefinisikan suatu listener bernama PerbesarListener yang mengimplementasikan ActionListener (baris 31-35).
2.  Menciptakan suatu listener dan meregistrasikannya dengan jbtPerbesar (baris 18).
3.  Menambahkan suatu metode bernama perbesar() di dalam PanelLingkaran untuk menambah radius, dan kemudian menggambar-ulang panel (baris 41-44).
4.  Mengimplementasikan metode actionPerformed di dalam PerbesarListener untuk memanggil kanvas.perbesar() (baris 33).
5.  Membuat variabel referensi kanvas agar dapat diakses dari metode actionPerformed, dan mendefinisikan PerbesarListener sebagai kelas inner (sebelah dalam) di dalam kelas KendaliLingkaran2 (baris 31-35). Kelas inner adalah kelas yang didefinisikan di dalam kelas lain.
6.  Untuk menghindari error kompolasi, kelas PanelLingkaran (baris 37-52) sekarang juga didefinisikan sebagai suatu kelas inner di dalam KendaliLingkaran2, karena kelas PanelLingkaran yang lama telah didefinisikan pada kode3.1.


Gambar 3.6 Pengguna mengklik tombol Perbesar dan Perkecil untuk memperbesar dan memperkecil radius suatu lingkaran


Kode3.2 KendaliLingkaran2.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class KendaliLingkaran2 extends JFrame {
  private JButton jbtPerbesar = new JButton("Perbesar");
  private JButton jbtPerkecil = new JButton("Perkecil");
  private PanelLingkaran kanvas = new PanelLingkaran();

  public KendaliLingkaran2() {
    JPanel panel = new JPanel(); // Menggunakan panel untuk mengelompokkan tombol
    panel.add(jbtPerbesar);
    panel.add(jbtPerkecil);

    this.add(kanvas, BorderLayout.CENTER); // Menambah kanvas ke tengah
    this.add(panel, BorderLayout.SOUTH); // Menambah tombol ke frame

    jbtPerbesar.addActionListener(new PerbesarListener());
  }

  /** Metode utama */
  public static void main(String[] args) {
    JFrame frame = new KendaliLingkaran2();
    frame.setTitle("KendaliLingkaran2");
    frame.setLocationRelativeTo(null); // Pusat frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(200, 200);
    frame.setVisible(true);
  }

  class PerbesarListener implements ActionListener {// Kelas inner
    public void actionPerformed(ActionEvent e) {
      kanvas.perbesar();
    }
  }

  class PanelLingkaran extends JPanel {// Kelas inner
    private int radius = 5; // Radius lingkaran default

    /** Perbesar lingkaran */
    public void perbesar() {
      radius++;
      repaint();
    }

    /** Menggambar-ulang lingkaran */
    protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.drawOval(getWidth() / 2 - radius, getHeight() / 2 - radius,
       2 * radius, 2 * radius);
    }
  }
}

Dengan cara yang sama, Anda dapat menambahkan kode untuk tombol Perkecil untuk menampilkan lingkaran lebih kecil ketika tombol Perkecil diklik.


3.4 Kelas Inner
Suatu kelas inner, kelas nested atau kelas sebelah dalam, adalah kelas yang didefinisikan di dalam skop kelas lain. Kode pada Gambar 3.7a mendefinisikan dua kelas terpisah, Test dan A. Kode pada Gambar 3.7b mendefinisikan A sebagai kelas inner di dalam kelas Test.

  
Gambar 3.7 Kelas-kelas inner mengkombinasikan kelas-kelas dependen ke dalam kelas primer


Kelas InnerClass yang didefinisikan di dalam kelas OuterClass pada Gambar 3.7c merupakan suatu contoh lain dari kelas inner. Kelas inner dapat digunakan sama seperti kelas biasa. Normalnya, Anda mendefinisikan suatu kelas sebagai kelas inner bila kelas tersebut hanya digunakan oleh kelas outernya. Suatu kelas inner memiliki fitur-fitur sebagai berikut:
·         Kelas inner dikompilasi ke dalam suatu kelas yang dinamakan NamaKelasOuter$NamaKelasInner.class. Sebagai contoh, kelas inner A di dalam Test dikompilasi ke dalam Test$A.class, seperti tertampil pada Gambar 3.7a.
·         Kelas inner dapat mereferensi metode dan data yang didefinisikan di dalam kelas outernya, sehingga Anda tidak perlu melewatkan referensi dari suatu objek kelas outer kepada konstruktor kelas inner. Karena hal ini, kelas inner dapat membuat program singkat dan padat.
·         Kelas inner dapat didefinisikan dengan suatu pemodifikasi visibilitas yang memiliki aturan yang sama dengan anggota kelas.
·         Kelas inner dapat didefinisikan static. Suatu kelas inner static dapat diakses menggunakan nama kelas outernya. Kelas inner static tidak dapat mengakses anggota-anggota kelas outer yang nonstatik.
·         Objek suatu kelas inner seringkali diciptakan di luar kelas outer. Tetapi Anda juga bisa menciptakan objek kelas inner di luar kelas lain. Jika kelas inner nonstaik, Anda terlebih dahulu menciptakan instans dari kelas outer, kemudian menggunakan sintaks berikut untuk menciptakan suatu objek untuk kelas inner:
KelasOuter.KelasInner objekInner = objekOuter.new KelasInner();

·         Jika kelas inner static, maka sintaks berikuti ini digunakan untuk menciptakan suatu objek untuk kelas inner:

KelasOuter.KelasInner objekInner = new KelasOuter.KelasInner();
Kegunaan sederhana dari kelas inner adalah menggabungkan kelas-kelas dependen ke dalam kelas primer. Hal ini akan mengurangi jumlah kode sumber. Hal ini juga membuat file-file kelas mudah untuk diorganisasi, karena semuanya dinamai dengan kelas primer sebagai prefiks. Sebagai contoh, daripada menciptakan dua file sumber, Test.java dan A.java, pada Gambar 3.7a, Anda dapat menggabungkan kelas A ke dalam kelas Test dan menciptakan hanya satu file sumber Test.java, seperti pada Gambar 3.7b. File kelas yang dihasilkan adalah Test.class dan Test$A.class.

Kegunaan lain dari kelas inner adalah untuk menghindari konflik penamaan kelas.


3.5 Listener Kelas Tak-Bernama
Suatu kelas listener didesain secara spesifik untuk menciptakan objek listener untuk komponen GUI tertentu (misalnya, suatu tombol). Kelas listener tidak dapat dipakai bersama oleh aplikasi-aplikasi lain dan oleh karena itu cocok untuk didefinisikan di dalam kelas frame sebagai kelas inner.

Listener kelas inner dapat disingkat menggunakan kelas inner tak-bernama. Terindikasi dari namanya, kelas inner tak-bernama adalah suatu kelas inner yang tidak memiliki nama. Kelas tersebut menggabungkan kelas inner dan menciptakan suatu instans dari kelas tersebut dalam satu langkah. Kelas inner pada kode3.2 dapat diganti dengan kelas inner tak-bernama, seperti ditunjukkan berikut ini.



 Sintaks untuk kelas inner tak-bernama adalah sebagai berikut:

new NamaKelasSuper/NamaAntarmuka() {
  // Metode pengimplementasi atau pengoverride di dalam kelas super atau antarmuka
  // Metode-metode lain jika diperlukan
}
Karena kelas inner tak-bernama merupakan kasus spesial dari suatu kelas inner, maka kelas ini diperlakukan sama dengan kelas inner lain dengan beberapa fitur tambahan sebagai berikut:
·         Kelas inner tak-bernama harus selalu mewarisi suatu superkelas atau mengimplementasikan suatu antarmuka, tetapi kelas ini tidak boleh memiliki klausa extends atau implements secara eksplisit.
·         Kelas inner tak-bernama harus mengimplementasikan semua metode abstrak yang ada di dalam kelas super atau di dalam antarmuka.
·         Kelas inner tak-bernama selalu menggunakan konstruktor tanpa-argumen dari superkelas untuk menciptakan suatu instans. Jika kelas inner tak-bernama mengimplementasikan antarmuka, maka konstruktornya adalah Object().
·         Kelas inner tak-bernama dikompilasi ke dalam suatu kelas bernama NamaKelasOuter$n.class. Sebagai contoh, dimisalkan kelas outer Test memiliki dua kelas inner tak-bernama, maka keduanya dikompilasi menjadi Test$1.class dan Test$2.class.
Kode3.3 menyajikan suatu contoh dalam menangani event-event dari empat tombol, seperti ditampilkan pada Gambar 3.8.

Kode3.3 DemoListenerTakBernama.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import javax.swing.*;
import java.awt.event.*;

public class DemoListenerTakBernama extends JFrame {
  public DemoListenerTakBernama() {
    // Menambahkan empat tombol
    JButton jbtBaru = new JButton("Baru");
    JButton jbtBuka = new JButton("Buka");
    JButton jbtSimpan = new JButton("Simpan");
    JButton jbtTampil = new JButton("Tampil");

    // Menciptakan panel untuk memuat empat tombol
    JPanel panel = new JPanel();
    panel.add(jbtBaru);
    panel.add(jbtBuka);
    panel.add(jbtSimpan);
    panel.add(jbtTampil);

    add(panel);

    // Menciptakan dan meregistrasi listener kelas inner tak-bernama
    jbtBaru.addActionListener(
      new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          System.out.println("Proses baru");
        }
      }
    );

    jbtBuka.addActionListener(
      new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          System.out.println("Proses membuka");
        }
      }
    );

    jbtSimpan.addActionListener(
      new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          System.out.println("Proses menyimpan");
        }
      }
    );

    jbtTampil.addActionListener(
      new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          System.out.println("Proses menampilkan");
        }
      }
    );
  }

  /** Metode utama */
  public static void main(String[] args) {
    JFrame frame = new DemoListenerTakBernama();
    frame.setTitle("DemoListenerTakBernama");
    frame.setLocationRelativeTo(null); // Pusat frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }
}


Gambar 3.8 Program menangani event dari empat tombol

Program menciptakan empat listener menggunakan kelas-kelas inner tak-bernama (baris 22-52). Tanpa menggunakan kelas inner tak-bernama, Anda harus menciptakan empat kelas yang berbeda. Kelas inner tak-bernama bekerja sama dengan kelas inner biasa.

Kelas inner tak-bernama dikompilasi menjadi NamaKelasOuter$#.class, dimana # dimulai dari 1 dan diinkremen setiap kali kompiler menemukan kelas inner tak-bernama. Pada contoh ini, kelas inner tak-bernama dikompilasi menjadi DemoListenerTakBernama$1.class,DemoListenerTakBernama$2.class,DemoListenerTakBernama$3.class, dan DemoListenerTakBernama$4.class.

Daripada menggunakan metode setSize() untuk menetapkan ukuran frame, program menggunakan metode pack() (baris 61), yang secara otomatis mengubah ukuran frame sesuai dengan ukuran komponen yang ditempatkan.


3.6 Cara Alternatif untuk Mendefinisikan Kelas Listener
Ada beberapa cara mendefinisikan kelas listener. Sebagai contoh, Anda diminta untuk menulis-ulang kode3.3 dengan menciptakan hanya satu listener, meregistrasi listener dengan tombol-tombol, dan mengijinkan listener untuk mendeteksi sumber event, misalnya tombol memicu event, seperti ditampilkan pada kode3.4.

Kode3.4 DemoDeteksiSumber.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import javax.swing.*;
import java.awt.event.*;

public class DemoDeteksiSumber extends JFrame {
  // Menciptakan empat tombol
  private JButton jbtBaru = new JButton("Baru");
  private JButton jbtBuka = new JButton("Buka");
  private JButton jbtSimpan = new JButton("Simpan");
  private JButton jbtTampil = new JButton("Tampil");

  public DemoDeteksiSumber() {
    // Menciptakan suatu panel untuk memuat tombol-tombol
    JPanel panel = new JPanel();
    panel.add(jbtBaru);
    panel.add(jbtBuka);
    panel.add(jbtSimpan);
    panel.add(jbtTampil);

    add(panel);

    // Menciptakan suatu listener
    ButtonListener listener = new ButtonListener();

    // Registrasi listener dengan tombol-tombol
    jbtBaru.addActionListener(listener);
    jbtBuka.addActionListener(listener);
    jbtSimpan.addActionListener(listener);
    jbtTampil.addActionListener(listener);
  }

  class ButtonListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if (e.getSource() == jbtBaru)
        System.out.println("Proses Baru");
      else if (e.getSource() == jbtBuka)
        System.out.println("Proses Buka");
      else if (e.getSource() == jbtSimpan)
        System.out.println("Proses Simpan");
      else if (e.getSource() == jbtTampil)
        System.out.println("Proses Tampil");
    }
  }

  /** Metode utama */
  public static void main(String[] args) {
    JFrame frame = new DemoDeteksiSumber();
    frame.setTitle("DemoDeteksiSumber");
    frame.setLocationRelativeTo(null); // Pusat frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    frame.setVisible(true);
  }
}

Program ini hanya mendefinisikan satu kelas listener inner (baris 31-42), menciptakan suatu listener dari kelas (baris 22), dan meregistrasikannya kepada empat tombol (baris 25-28). Ketika suatu tombol diklik, tombol memicu suatu ActionEvent dan memanggil metode actionPerformed dari listener. Metode actionPerformed memeriksa sumber event menggunakan metode getSource() untuk event (baris 33, 35, 37, dan 39) dan menentukan tombol mana yang memicu event terkait. Anda juga bisa menulis-ulang kode3.3 dengan mendefinisikan kelas frame yang mengimplementasikan ActionListener, seperti ditunjukkan pada kode3.5.


Kode3.5 DemoListenerSebagaiFrame.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import javax.swing.*;
import java.awt.event.*;

public class DemoListenerSebagaiFrame extends JFrame
    implements ActionListener {
  // Menciptakan empat tombol
  private JButton jbtBaru = new JButton("Baru");
  private JButton jbtBuka = new JButton("Buka");
  private JButton jbtSimpan = new JButton("Simpan");
  private JButton jbtTampil = new JButton("Tampil");

  public DemoListenerSebagaiFrame() {
    // Menciptakan suatu panel untuk memuat tombol-tombol
    JPanel panel = new JPanel();
    panel.add(jbtBaru);
    panel.add(jbtBuka);
    panel.add(jbtSimpan);
    panel.add(jbtTampil);

    add(panel);

    // Registrasi listener dengan tombol-tombol
    jbtBaru.addActionListener(this);
    jbtBuka.addActionListener(this);
    jbtSimpan.addActionListener(this);
    jbtTampil.addActionListener(this);
  }

  // Mengimplementasikan metode actionPerformed
  public void actionPerformed(ActionEvent e) {
    if (e.getSource() == jbtBaru)
      System.out.println("Proses Baru");
    else if (e.getSource() == jbtBuka)
      System.out.println("Proses Buka");
    else if (e.getSource() == jbtSimpan)
      System.out.println("Proses Simpan");
    else if (e.getSource() == jbtTampil)
      System.out.println("Proses Tampil");
  }

  /** Metode utama */
  public static void main(String[] args) {
    JFrame frame = new DemoListenerSebagaiFrame();
    frame.setTitle("DemoListenerSebagaiFrame");
    frame.setLocationRelativeTo(null); // Pusat frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    frame.setVisible(true);
  }
}


Kelas frame mewarisi JFrame dan mengimplementasikan ActionListener (baris 5). Jadi kelas tersebut adalah kelas listener untuk event-event aksi. Listener diregistrasi dengan empat tombol (baris 23-26). Ketika suatu tombol diklik, tombol tersebut memicu suatu ActionEvent dan memanggil metode actionPerformed dari listener. Metode actionPerformed memeriksa sumber event menggunakan metode getSource() untuk event (baris 31, 35, dan 37) dan menentukan tombol mana yang memicu event.

3.7 Masalah: Kalkulator Hutang
Sekarang Anda dapat menulis program untuk kalkulator hutang. Berikut adalah langkah-langkah utama program:
1.  Menciptakan suatu antarmuka pengguna, seperti tertampil pada Gambar 3.9.
a)  Menciptakan suatu panel GridLayout dengan 5 baris dan 2 kolom. Tambahkan label dan bidang teks ke dalam panel. Tetapkan judul “Masukkan jumlah pinjaman, suku bunga, dan jumlah tahun”pada panel.
b)  Menciptakan suatu panel lain dengan FlowLayout(FlowLayout.RIGHT) dan tambahkan suatu tombol ke dalam panel.
c)  Menempatkan panel pertama ke tengah frame dan panel kedua ke bagian selatan frame.
2.  Memproses event.
Menciptakan dan meregistrasi listener untuk memproses event aksi pengklikan tombol. Handler kemudian memperoleh masukan pengguna untuk pinjaman, suku bunga, dan jumlah tahun, menghitung pembayaran bulanan dan pembayaran total, dan menampilkan nilai-nilai di dalam bidang-bidang teks.


Gambar 3.9 Program menghitung pembayaran hutang


Program utuh ditampilkan pada kode3.6.

Kode3.6 KalkulatorHutang.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;

public class KalkulatorHutang extends JFrame {
  // Menciptakan bidang teks untuk suku bunga,
  // tahun, jumlah pinjaman, pembayaran bulanan, dan pembayaran total
  private JTextField jtfSukuBungaTahunan = new JTextField();
  private JTextField jtfJumlahTahun = new JTextField();
  private JTextField jtfJumlahPinjaman = new JTextField();
  private JTextField jtfPembayaranBulanan = new JTextField();
  private JTextField jtfPembayaranTotal = new JTextField();

  // Menciptakan suatu tombol Hitung Pembayaran
  private JButton jbtHitungHutang = new JButton("Hitung Pembayaran");

  public KalkulatorHutang() {
    // Panel p1 untuk memua label dan bidang teks
    JPanel p1 = new JPanel(new GridLayout(5, 2));
    p1.add(new JLabel("Suku Bunga Tahunan"));
    p1.add(jtfSukuBungaTahunan);
    p1.add(new JLabel("Jumlah Tahun"));
    p1.add(jtfJumlahTahun);
    p1.add(new JLabel("Jumlah Pinjaman"));
    p1.add(jtfJumlahPinjaman);
    p1.add(new JLabel("Pembayaran Bulanan"));
    p1.add(jtfPembayaranBulanan);
    p1.add(new JLabel("Pembayaran Total"));
    p1.add(jtfPembayaranTotal);
    p1.setBorder(new
      TitledBorder("Masukkan jumlah pinjaman, suku bunga, dan jumlah tahun"));

    // Panel p2 untuk memuat tombol
    JPanel p2 = new JPanel(new FlowLayout(FlowLayout.RIGHT));
    p2.add(jbtHitungHutang);

    // Menambah panel ke frame
    add(p1, BorderLayout.CENTER);
    add(p2, BorderLayout.SOUTH);

    // Register listener
    jbtHitungHutang.addActionListener(new ButtonListener());
  }

  /** Menangani tombol Hitung Pembayaran */
  private class ButtonListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      // Mendapatkan nilai-nilai dari bidang teks
      double bunga =
        Double.parseDouble(jtfSukuBungaTahunan.getText());
      int tahun =
        Integer.parseInt(jtfJumlahTahun.getText());
      double jumlahPinjaman =
        Double.parseDouble(jtfJumlahPinjaman.getText());

      // Menciptakan suatu objek hutang
      Hutang hutang = new Hutang(bunga, tahun, jumlahPinjaman);

      // Menghitung pembayaran bulanan dan pembayaran total
      jtfPembayaranBulanan.setText(String.format("%.2f",
        hutang.dapatPembayaranBulanan()));
      jtfPembayaranTotal.setText(String.format("%.2f",
        hutang.dapatPembayaranTotal()));
    }
  }

  public static void main(String[] args) {
  KalkulatorHutang frame = new KalkulatorHutang();
  frame.pack();
  frame.setTitle("KalkulatorHutang");
  frame.setLocationRelativeTo(null); // Pusat frame
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frame.setVisible(true);
  }
}

Hutang.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class Hutang {
  private double sukuBungaTahunan;
  private int jumlahTahun;
  private double jumlahPinjaman;
  private java.util.Date tanggalPinjaman;

  /** Konstruktor Default */
  public Hutang() {
    this(2.5, 1, 1000);
  }

  /** Menciptakan suatu objek Hutang dengan suku bunga tahunan,
      jumlah tahun, dan jumlah pinjaman tertentu
   */
  public Hutang(double sukuBungaTahunan, int jumlahTahun,
    double jumlahPinjaman){
  this.sukuBungaTahunan = sukuBungaTahunan;
  this.jumlahTahun = jumlahTahun;
  this.jumlahPinjaman = jumlahPinjaman;
  tanggalPinjaman = new java.util.Date();
  }

  /** Mengembalikan sukuBungaTahunan */
  public double dapatSukuBungaTahunan() {
    return sukuBungaTahunan;
  }

  /** Menetapkan sukuBungaTahunan yang baru */
  public void tetapkanSukuBungaTahunan(double sukuBungaTahunan) {
    this.sukuBungaTahunan = sukuBungaTahunan;
  }

  /** Mengembalikan jumlahTahun */
  public int dapatJumlahTahun() {
    return jumlahTahun;
  }

  /** Menetapkan jumlahTahun yang baru */
  public void tetapkanJumlahTahun(int jumlahTahun) {
    this.jumlahTahun = jumlahTahun;
  }

  /** Mengembalikan jumlahPinjaman */
  public double dapatJumlahPinjaman() {
    return jumlahPinjaman;
  }

  /** Menetapkan jumlahPinjaman yang baru*/
  public void tetapkanJumlahPinjaman(double jumlahPinjaman) {
    this.jumlahPinjaman = jumlahPinjaman;
  }

  /** Menghitung pembayaran bulanan */
  public double dapatPembayaranBulanan() {
    double sukuBungaBulanan = sukuBungaTahunan / 1200;
    double pembayaranBulanan = jumlahPinjaman * sukuBungaBulanan / (1 -
     (Math.pow(1 / (1 + sukuBungaBulanan), jumlahTahun * 12)));
    return pembayaranBulanan;
  }

  /** Menghitung total pembayaran */
  public double dapatPembayaranTotal() {
    double pembayaranTotal = dapatPembayaranBulanan() * jumlahTahun * 12;
    return pembayaranTotal;
  }

  /** Mengembalikan tanggal pinjaman */
  public java.util.Date dapatTanggalPinjaman() {
    return tanggalPinjaman;
  }
}

Antarmuka pengguna diciptakan di dalam konstruktor (baris 18-44). Tombol merupakan sumber event. Suatu listener diciptakan dan diregistrasi dengan tombol (baris 43).

Kelas listener (baris 47-66) mengimplementasikan metode actionPerformed. Ketika tombol diklik, metode actionPerformed dipanggil untuk mendapatkan suku bunga (baris 51), jumlah tahun (baris 53), dan jumlah pinjaman (baris 55). Pemanggilan jtfSukuBungaTahunan.getText() akan mengembalikan teks string di dalam bidang teks jtfSukuBungaTahunan. hutang digunakan untuk menghitung pembayaran hutang. Pemanggilan hutang.dapatPembayaranBulanan() mengembalikan pembayaran bulanan. Metode String.format menggunakan sintaks seperti printf untuk memformat suatu angka menjadi format yang diinginkan. Pemanggilan metode setText pada suatu bidang teks menetapkan nilai string pada bidang bidang teks tersebut.

3.8 Event Jendela
Beberapa bagian yang terdahulu membahas beberapa event aksi. Event-event lainnya dapat diproses dengan cara yang sama. Bagian ini akan menyajikan contoh penanganan WindowEvent. Sembarang subkelas dari kelas Window dapat memicu beberapa event jendela berikut: Jendela dibuka, dicoba untuk ditutup, ditutup, diaktivasi, dideaktivasi, diikonfikasi, dan dideikonifikasi. Program pada kode3.7 menciptakan suatu frame, merespon event-event jendela, dan menampilkan pesan untuk mengindikasikan event yang sedang terjadi. Gambar 3.10 menunjukkan suatu contoh hasil keluaran program.


Gambar 3.10 Beberapa event jendela ditampilkan pada konsol ketika Anda menjalankan program dari command prompt


Kode3.7 UjiEventJendela.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import java.awt.event.*;
import javax.swing.JFrame;

public class UjiEventJendela extends JFrame {
  public static void main(String[] args) {
    UjiEventJendela frame = new UjiEventJendela();
    frame.setSize(220, 80);
    frame.setLocationRelativeTo(null); // Pusat frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setTitle("UjiEventJendela");
    frame.setVisible(true);
  }

  public UjiEventJendela() {
    addWindowListener(new WindowListener() {
      /**
       * Handler untuk event deikonifikasi jendela
       * Dipanggil ketika suatu jendela diubah dari keadaaan terminimisasi
       * menjadi keadaan normal.
       */
      public void windowDeiconified(WindowEvent event) {
        System.out.println("Jendela dideikonifikasi");
      }

      /**
       * Handler untuk event ikonifikasi jendela
       * Dipanggil ketika suatu jendela diubah dari keadaan normal
       * menjadi keadaan terminimisasi. Pada banyak platform, jendela terminimisasi
       * ditampilkan sebagai ikon tertentu pada properti
       * iconImage jendela.
       */
      public void windowIconified(WindowEvent event) {
        System.out.println("Jendela diikonifikasi");
      }

      /**
       * Handler untuk event aktifasi jendela
       * Dipanggil ketika jendela ditetapkan menjadi jendela aktif
       * bagi pengguna, berarti bahwa jendela (atau salah satu dari
       * sub-subkomponennya) akan menerima event papankunci (keyboard).
       */
      public void windowActivated(WindowEvent event) {
        System.out.println("Jendela diaktivasi");
      }

      /**
       * Handler untuk event deaktivasi jendela
       * Dipanggil ketika jendela tidak lagi menjadi jendela aktif
       * bagi pengguna, berarti bahwa event papankunci tidak lagi
       * dikirim kepada jendela atau sub-subkomponennya.
       */
      public void windowDeactivated(WindowEvent event) {
        System.out.println("Jendela dideaktivasi");
      }

      /**
       * Handler untuk event pembukaan jendela
       * Dipanggil saat pertama kali jendela terlihat atau muncul.
       */
      public void windowOpened(WindowEvent event) {
        System.out.println("Jendela dibuka");
      }

      /**
       * Handler untuk event percobaan penutupan jendela
       * Dipanggil ketika pengguna mencoba untuk menutup jendela
       * dari menu sistem jendela. Jika program tidak secara eksplisit
       * menyembunyikan atau menutup jendela pada saat memproses
       * event ini, operasi penutupan jendela akan dibatalkan.
       */
      public void windowClosing(WindowEvent event) {
        System.out.println("Jendela akan ditutup");
      }

      /**
       * Handler untuk event penutupan jendela
       * Dipanggil ketika jendela telah ditutup akibat hasil dari
       * pemanggilan handler percobaaan penutupan jendela.
       */
      public void windowClosed(WindowEvent event) {
        System.out.println("Jendela ditutup");
      }
    });
  }
}

WindowEvent dapat dipicu oleh kelas Window atau oleh sembarang subkelas dari Window. Karena JFrame merupakan subkelas dari Window, maka JFrame dapat memicu WindowEvent.

UjiEventJendela mewarisi JFrame dan mengimplementasikan WindowListener. Antarmuka WindowListener mendefinisikan beberapa metode abstrak (windowActivated, windowClosed, windowClosing, windowDeactivated, windowDeiconified, windowIconified, windowOpened) untuk menangani event-event jendela ketika jendela diaktivasi, ditutup, dicoba untuk ditutup, dideaktivasi, dideikonifikasi, diikonifikasi, atau dibuka.

Ketika suatu event jendela, seperti aktivasi, terjadi, metode windowActivated dipanggil. Anda bisa mengimplementasikan metode windowActivated dengan suatu respon konkrit jika Anda menginginkan event terkait diproses.

3.9 Adapter Antarmuka Listener
Karena metode-metode di dalam antarmuka WindowListener adalah abstrak, Anda harus mengimplementasikan semua metode tersebut meskipun program Anda tidak peduli tentang beberapa event yang ada. Untuk mengatasi kelelahan tersebut, JAVA menyediakan beberapa kelas pendukung, yang disebut dengan adapter, yang menyediakan implementasi-implementasi default untuk semua metode di dalam antarmuka listener. Implementasi default hanya berupa tubuh kosong. JAVA menyediakan adapter listener untuk setiap antarmuka listener AWT dengan beberapa handler. Adapter-adapter tersebut dinamai XAdapter untuk XListener. Sebagai contoh, WindowAdapter adalah adapter listener untuk WindowListener. Tabel 3.3 mencantumkan beberapa adapter yang sering dijumpai.

Tabel 3.3 Beberapa Adapter Penting
Adapter
Antarmuka
WindowAdapter
MouseAdapter
MouseMotionAdapter
KeyAdapter
ContainerAdapter
ComponentAdapter
FocusAdapter
WindowListener
MouseListener
MouseMotionListener
KeyListener
ContainerListener
ComponentListener
FocusListener

Dengan menggunakan WindowAdapter, contoh terdahulu dapat disederhanakan seperti ditampilkan pada kode3.8, jika Anda hanya tertarik pada event jendela. Kelas WindowAdapter digunakan untuk menciptakan suatu listener tak-bernama, bukan WindowListener (baris 15). Handler windowActivated diimplementasikan pada baris 16.

Kode3.8 DemoAdapter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.awt.event.*;
import javax.swing.JFrame;

public class DemoAdapter extends JFrame {
  public static void main(String[] args) {
    DemoAdapter frame = new DemoAdapter();
    frame.setSize(220, 80);
    frame.setLocationRelativeTo(null); // Pusat frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setTitle("DemoAdapter");
    frame.setVisible(true);
 }

  public DemoAdapter() {
    addWindowListener(new WindowAdapter() {
      public void windowActivated(WindowEvent event) {
        System.out.println("Jendela diaktivasi");
      }
    });
  }
}

3.10 Event Mouse
Suatu event mouse dipicu manakala mouse ditekan, dilepas, diklik, digerakkan, digeret pada suatu komponen. Objek MouseEvent menangkap event tersebut, seperti jumlah klik yang terkait atau lokasi (koordinat x dan y) dari mouse, seperti ditampilkan pada Gambar 3.11.
Karena kelas MouseEvent mewarisi InputEvent, Anda dapat menggunakan metode-metode yang didefinisikan di dalam kelas InputEvent pada objek MouseEvent.

Kelas java.awt.Point merepresentasikan titik pada suatu komponen. Kelas ini memuat dua variabel, x dan y, yang merepresentasikan koordinat. Untuk menciptakan suatu Point, digunakan konstruktor berikut:

Point(int x, int y)

Konstruktor ini menciptakan suatu objek Point dengan koordinat x dan y tertentu. Normalnya, bidang-bidang data dalam suatu kelas dideklarasikan privat, tetapi pada kelas Point ini, dua bidang data dideklarasikan publik.

JAVA menyediakan dua antarmuka listener, MouseListener dan MouseMotionListener, untuk menangani event-event mouse, seperti ditunjukkan pada Gambar 3.12. Antarmuka MouseListener diimplementasikan untuk memproses event-event, seperti aksi menekan, melepas, memasukkan, mengeluarkan, atau mengklik mouse, dan MouseMotionListener diimplementasikan untuk memproses event-event, seperti aksi menggeret atau menggerakkan mouse.

Gambar 3.11 Kelas MouseEvent mengenkapsulasi informasi untuk event-event mouse


3.10.1 Contoh: Menggerakkan Pesan Pada Panel Dengan Mouse
Contoh ini akan menyajikan suatu program yang menampilkan pesan di dalam suatu panel, seperti tertampil pada Gambar 3.9. Anda dapat menggunakan mouse untuk menggerakkan pesan. Pesan bergerak bila digeret oleh mouse dan selalu ditampilkan pada ujung penunjuk mouse. Hasil keluaran program ditampilkan pada Gambar 3.13.



Gambar 3.12 Antarmuka MouseListener menangani saat mouse ditekan, dilepas,


Gambar 3.13 Anda bisa memindahkan pesan dengan cara menggeret mouse


Kode3.9 DemoGerakPesan.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class DemoGerakPesan extends JFrame {
  public DemoGerakPesan() {
    // Menciptakan suatu instans PanelGerakPesan untuk memindahkan pesan
    PanelGerakPesan p = new PanelGerakPesan
     ("JAVA itu Tangguh!");

    // Menempatkan panel pesan di dalam frame
    setLayout(new BorderLayout());
    add(p);
  }

  /** Metode utama */
  public static void main(String[] args) {
    DemoGerakPesan frame = new DemoGerakPesan();
    frame.setTitle("DemoGerakPesan");
    frame.setSize(200, 100);
    frame.setLocationRelativeTo(null); // Pusat frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }

  // Kelas inner: PanelGerakPesan menggambar pesan
  static class PanelGerakPesan extends JPanel {
    private String pesan = "JAVA itu Tangguh!";
    private int x = 20;
    private int y = 20;

    /** Menciptakan suatu panel untuk menggambar string s */
    public PanelGerakPesan(String s) {
      pesan = s;
      addMouseMotionListener(new MouseMotionAdapter() {
        /** Menangani event penggeretan mouse */
        public void mouseDragged(MouseEvent e) {
          // Mendapatkan lokasi baru dan menggambar di layar
          x = e.getX();
          y = e.getY();
          repaint();
        }
      });
    }

    /** Menggambar komponen */
    protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.drawString(pesan, x, y);
    }
  }
}

Kelas PanelGerakPesan mewarisi JPanel untuk menggambarkan suatu pesan (baris 27). Kelas tersebut menampilkan-ulang pesan ulang ketika pesan digeret menggunakan mouse.Kelas ini didefinisikan di dalam sebagai kelas inner di dalam kelas main karena hanya digunakan di dalam kelas tersebut. Dan lagi, kelas inner tersebut didefinisikan statik karena tidak mereferensi sembarang anggota instans dari kelas main.

Antarmuka MouseMotionListener memuat dua handler, mouseMoved dan mouseDragged, untuk menangani event-event pergerakan mouse. Ketika Anda menggerakkan mouse dengan tombol ditekan, metode mouseDragged dipanggil untuk menggambar-ulang layar dan menampilkan pesan pada ujung penunjuk mouse. Ketika Anda menggerakkan mouse tanpa menekannya, metode mouseMoved dipanggil.

Karena listener hanya tertarik pada event penggeretan mouse, listener kelas inner tak-bernama mewarisi MouseMotionAdapter untuk mengoverride metode mouseDragged. Jika kelas inner mengimplementasikan antarmuka MouseMotionListener, maka Anda harus mengimplementasikan semua handler, meskipun jika handler Anda tidak peduli dengan beberapa event.  

Metode mouseDragged dipanggil ketika Anda menggerakkan mouse dengan tombol ditekan. Metode ini mendapatkan lokasi mouse menggunakan metode getX dan getY (baris 39-40) di dalam kelas MouseEvent. Lokasi tersebut menjadi lokasi baru bagi pesan. Pemanggilan metode repaint() (baris 41) menyebabkan paintComponent menjadi dipanggil (baris 47), yang menampilkan pesan pada lokasi baru.


3.11 Event Kunci
Event kunci memampukan penggunaan kunci-kunci untuk mengendalikan dan melakukan aksi atau mendapatkan masukan dari papankunci. Event kunci dipicu ketika suatu kunci ditekan, dilepas, atau diketik pada suatu komponen. Objek KeyEvent mendeskripsikan keadaan event (misalnya, kunci ditekan, dilepas, atau diketikkan) dan nilai kunci, seperti ditampilkan pada Gambar 3.14. JAVA menyediakan antarmuka KeyListener untuk menangani event-event kunci, seperti ditampilkan pada Gambar 3.15.



Gambar 3.14 Kelas KeyEvent mengenkapsulasi informasi tentang event-event kunci



Gambar 3.15 Antarmuka KeyListener menangani event kunci dilepas, ditekan, dan diketikkan


Handler keyPressed dipanggil ketika kunci ditekan, handler keyReleased dipangil ketika kunci dilepas, dan handler keyTyped dipanggil ketika suatu karakter Unicode dientrikan. Jika suatu kunci tidak memiliki Unicode (kunci fungsi, kunci pemodifikasi, kunci aksi, dan kunci kendali), maka handler keyTyped tidak akan dipanggil. Setiap event kunci memiliki karakter kunci terkait atau kode kunci yang dikembalikan oleh metode getKeyChar() atau getKeyCode(). Kode kunci adalah konstanta yang didefinisikan di dalam Tabel 3.4.

Tabel 3.4 Konstanta-Konstanta Kunci
Konstanta
Deskripsi
Konstanta
Deskripsi
VK_HOME
VK_END
VK_PGUP
VK_PGDN
VK_UP
VK_DOWN
VK_LEFT
VK_RIGHT
VK_ESCAPE
VK_TAB
VK_CONTROL
Kunci Home
Kunci End
Kunci Page Up
Kunci Page Down
Kunci Up-Arrow
Kunci Down-Arrow
Kunci Left-Arrow
Kunci Right-Arrow
Kunci Escape
Kunci Tab
Kunci Control
VK_SHIFT
VK_BACK_SPACE
VK_CAPS_LOCK
VK_NUM_LOCK
VK_ENTER
VK_UNDEFINED
VK_F1 sampai VK_F12
VK_0 sampai VK_9
VK_A sampai VK_Z
Kunci Shift
Kunci Backspace
Kunci Caps Lock
Kunci Num Lock
Kunci Enter
Kunci tidak dikenali
Kunci Fungsi F1 sampai F12
Kunci angka 0 sampai 9
Kunci Huruf A sampai Z

Untuk event penekanan-kunci dan pelepasan-kunci, getKeyCode() mengembalikan nilai seperti didefinisikan di dalam Tabel 3.4. Untuk event pengetikan-kunci, metode getKeyCode() mengembalikan VK_UNDEFINED, sedangkan getKeyChar() mengembalikan karakter yang dientrikan.

Program pada kode3.10 menampilkan suatu karakter yang dientri oleh pengguna. Pengguna dapat memindahkan karakter ke atas, ke bawah, ke kiri, dan ke kanan, menggunakan kunci panah VK_UP, VK_DOWN, VK_LEFT, dan VK_RIGHT. Gambar 3.16 menampilkan hasil keluaran program.


Gambar 3.16 Program merespon event kunci dengan menampilkan suatu karakter dan menggerakkannya ke atas, ke bawah, ke kiri, dan ke kanan


Kode3.10 DemoEventKunci.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class DemoEventKunci extends JFrame {
  private PanelPapanKunci panelPapanKunci = new PanelPapanKunci();

  /** Menginisialisasi */
  public DemoEventKunci() {
    // Menambahkan panel papankunci untuk menerima dan menampilkan masukan pengguna
    add(panelPapanKunci);

    // Menetapkan fokus
    panelPapanKunci.setFocusable(true);
  }

  /** Metode utama */
  public static void main(String[] args) {
    DemoEventKunci frame = new DemoEventKunci();
    frame.setTitle("DemoEventKunci");
    frame.setSize(300, 300);
    frame.setLocationRelativeTo(null); // Pusat frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }

  // Kelas inner: PanelPapanKunci untuk menerima masukan kunci
  static class PanelPapanKunci extends JPanel {
    private int x = 100;
    private int y = 100;
    private char karKunci = 'J'; // Kunci default

    public PanelPapanKunci() {
      addKeyListener(new KeyAdapter() {
        public void keyPressed(KeyEvent e) {
          switch (e.getKeyCode()) {
            case KeyEvent.VK_DOWN: y += 10; break;
            case KeyEvent.VK_UP: y -= 10; break;
            case KeyEvent.VK_LEFT: x -= 10; break;
            case KeyEvent.VK_RIGHT: x += 10; break;
            default: karKunci = e.getKeyChar();
          }

          repaint();
        }
      });
    }

    /** Menggambar karakter */
    protected void paintComponent(Graphics g) {
      super.paintComponent(g);

      g.setFont(new Font("TimesRoman", Font.PLAIN, 24));
      g.drawString(String.valueOf(karKunci), x, y);
    }
  }
}

Kelas PanelPapanKunci mewarisi JPanel untuk menampilkan suatu karakter (baris 28). Kelas ini didefinisikan sebagai kelas inner di dalam kelas utama, karena hanya digunakan di dalam kelas utama tersebut. Juga, kelas inner tersebut didefinisikan statik, karena tidak mereferensi sembarang anggota instans dari kelas main.

Karena program memperoleh masukan dari papankunci, program akan merespon KeyEvent dan mewarisi KeyAdapter untuk menangani masukan kunci (baris 34).

Ketika suatu kunci ditekan, handler keyPressed dipanggil. Program menggunakan e.getKeyCode() untuk mendapatkan kode kunci dan e.getKeyChar() untuk mendapatkan karakter untuk kunci. Ketika kunci non-panah ditekan, karakter ditampilkan (baris 41). Ketika kunci panah ditekan, maka karakter bergerak pada arah yang diindikasikan oleh kunci panah (baris 37-40).

Hanya komponen yang fokus saja yang bisa menerima KeyEvent. Untuk membuat komponen menjadi fokus, properti isFocusable ditetapkan bernilai true (baris 14).

3.12 Animasi menggunakan Kelas Timer
Tidak semua objek sumber merupakan komponen GUI. Kelas javax.swing.Timer adalah suatu komponen sumber yang memicu ActionEvent pada laju yang telah ditetapkan. Gambar 3.17 mencantumkan beberapa metode di dalam kelas ini.


Gambar 3.17 Suatu objek Timer memicu ActionEvent pada laju tetap


Objek Timer berperan sebagai sumber suatu ActionEvent. Listener harus merupakan instans dari ActionListener dan diregistrasi dengan suatu objek Timer. Anda dapat menciptakan objek Timer menggunakan konstruktornya dengan suatu tunda dan suatu listener, dimana delay menspesifikasi jumlah milidetik di antara dua event aksi. Anda dapat menambahkan listener tambahan menggunakan metode addActionListener dan mengubah delay menggunakan metode setDelay. Untuk memulai timer, metode start() perlu dipanggil. Untuk menghentikan timer, metode stop() perlu dipanggil.

Kelas Timer dapat digunakan untuk mengendalikan animasi. Sebagai contoh, Anda dapat menggunakannya untuk menampilkan suatu pesan bergerak, seperti yang tertampil pada Gambar 3.18, dengan kode3.11.


Kode3.11 DemoAnimasi.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class DemoAnimasi extends JFrame {
  public DemoAnimasi() {
    // Menciptakan suatu PanelPesanBergerak untuk menampilkan suatu pesan bergerak
    add(new PanelPesanBergerak("Pesan bergerak?"));
  }

  /** Metode utama */
  public static void main(String[] args) {
    DemoAnimasi frame = new DemoAnimasi();
    frame.setTitle("DemoAnimasi");
    frame.setSize(280, 100);
    frame.setLocationRelativeTo(null); // Pusat frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }

  // Kelas inner: Menampilkan suatu pesan bergerak
  static class PanelPesanBergerak extends JPanel {
    private String pesan = "JAVA itu Tangguh!";
    private int xKoordinat = 0;
    private int yKoordinat = 20;

    public PanelPesanBergerak(String pesan) {
      this.pesan = pesan;

      // Menciptakan suatu timer
      Timer timer = new Timer(1000, new TimerListener());
      timer.start();
    }

    /** Menggambar pesan */
    protected void paintComponent(Graphics g) {
      super.paintComponent(g);

      if (xKoordinat > getWidth()) {
        xKoordinat = -20;
      }
      xKoordinat += 5;
      g.drawString(pesan, xKoordinat, yKoordinat);
    }

    class TimerListener implements ActionListener {
      /** Menangani ActionEvent */
      public void actionPerformed(ActionEvent e) {
        repaint();
      }
    }
  }
}

Kelas PanelPesanBergerak mewarisi JPanel untuk menampilkan suatu pesan (baris 22). Kelas ini didefinisikan sebagai kelas inner di dalam kelas utama, karena hanya digunakan di dalam kelas utama tersebut saja. Dan, kelas inner tersebut didefinisikan statik, karena tidak mereferensi sembarang anggota instans dari kelas utama.

Suatu listener kelas inner didefinisikan pada baris 46 untuk merespon ActionEvent. Baris 31 menciptakan suatu Timer untuk listener tersebut. Timer dimulai pada baris 32 dan memicu suatu ActionEvent setiap detik, dan listener meresponnya pada baris 49 untuk menggambar-ulang panel. Ketika panel digambar, koordinat x diinkremen (baris 42), sehingga pesan ditampilkan ke kanan. Ketika koordinat x melebihi batas panel, maka koordinat x ditetapkan-ulang menjadi -20 (baris 40), sehingga pesan terus bergerak dari kiri ke kanan.

Pada kode3.12 akan didemonstrasikan mendesain program untuk menggambarkan jam yang sedang berdetak. Apa yang Anda lakukan agar jam menampilkan suatu waktu sekarang yang baru pada setiap detik? Untuk membuat jam berdetak setiap detik, Anda harus menggambarkan-ulang jam tersebut setiap detik dengan waktu sekarang yang terperbarui. Anda bisa menggunakan suatu timer untuk mengendalikan penggambaran-ulang jam.

Kode3.12 AnimasiJam.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import java.awt.event.*;
import javax.swing.*;

public class AnimasiJam extends JFrame {
  private JamDiam jam = new JamDiam();

  public AnimasiJam() {
    add(jam);

    // Menciptakan suatu timer dengan tunda 1000 ms
    Timer timer = new Timer(1000, new TimerListener());
    timer.start();
  }

  private class TimerListener implements ActionListener {
    /** Menangani event aksi */
    public void actionPerformed(ActionEvent e) {
      // Menetapkan waktu baru dan menggambar-ulang jam, menampilkan waktu sekarang
      jam.tetapkanWaktuSekarang();
      jam.repaint();
    }
  }

  /** Metode utama */
  public static void main(String[] args) {
    JFrame frame = new AnimasiJam();
    frame.setTitle("AnimasiJam");
    frame.setSize(200, 200);
    frame.setLocationRelativeTo(null); // Pusat frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }
}

Program menampilkan suatu jam yang berdetak, seperti tertampil pada Gambar 3.19. Kelas AnimasiJam menciptakan JamDiam (baris 5). Baris 11 menciptakan Timer untuk AnimasiJam. Timer dimulai pada baris 12. Timer memicu suatu ActionEvent setiap detik, dan listener merespon untuk menetapkan suatu waktu baru (baris 19) dan menggambar-ulang jam (jam 20). Metode setCurrentTime() yang didefinisikan di dalam JamDiam menetapkan waktu sekarang di dalam jam.


Gambar 3.19 Suatu jam berdetak ditampilkan di dalam panel



















No comments:

Post a Comment