Menempatkan komponen dengan koordinat piksel tetap (setBounds(10, 20, 80, 25)) terasa mudah — sampai jendela diubah ukurannya, teks memanjang setelah ganti bahasa, atau aplikasi dibuka di layar berbeda ketebalannya. Swing menolak pendekatan itu dan menyerahkan penataan kepada layout manager: objek yang menghitung posisi serta ukuran setiap komponen setiap kali ruang tersedia berubah. Kita hanya menyatakan aturan — “tombol-tombol ini sejajar ke kanan”, “tabel ini mengisi ruang tengah” — dan layout manager mengerjakan aritmetika. Chapter ini membedah lima layout manager inti beserta karakternya, lalu membuktikan bahwa perhitungan letak bisa diuji tanpa membuka jendela nyata.

Cara Kerja Layout Manager #

Setiap JPanel lahir bersama satu layout manager (FlowLayout sebagai bawaan) yang duduk di antara panel dan anak-anaknya. Saat sebuah container perlu ditata — karena pack() mengukurnya, setSize() dipanggil, atau pengguna mengubah ukuran jendela — terjadi dua putaran hitung. Pertama, layout manager menanyai setiap anak tentang preferred size, minimum size, dan maximum size milik anak itu, lalu menghitung preferred size container itu sendiri. Kedua, ketika ukuran container yang sebenarnya diketahui, layout manager membagikan ruang nyata itu kepada anak-anak lewat pemanggilan setBounds pada tiap anak. Karena kedua putaran berjalan di atas angka murni, kita bisa memicu tata letak secara manual dengan setSize(...) lalu doLayout() lalu membaca hasil koordinatnya — teknik yang dipakai seluruh contoh runnable chapter ini.

Lima Layout Manager Utama #

LayoutGaya penataanCocok untuk
FlowLayoutBaris yang mengalir kiri ke kanan, membungkus ke baris baruDeretan tombol
BorderLayoutLima wilayah: NORTH, SOUTH, EAST, WEST, CENTERKerangka aplikasi
GridLayoutGrid sel sama besar, terisi kiri ke kanan lalu turunPapan tombol, kalender
GridBagLayoutGrid fleksibel: sel boleh melebar beberapa baris/kolomFormulir kompleks
BoxLayoutSatu sumbu — vertikal atau horizontal — dengan perekatBilah samping, panel bertumpuk

Berikut wujud ketiganya dalam kode. FlowLayout adalah default JPanel, jadi panel pertama bahkan tidak menyebut layout apa pun:

java PanelFlow.java — FlowLayout tanpa pengaturan eksplisit
import javax.swing.JButton;
import javax.swing.JPanel;

public class PanelFlow {
    public static JPanel bangun() {
        JPanel panel = new JPanel(); // FlowLayout bawaan
        panel.add(new JButton("Tambah"));
        panel.add(new JButton("Hapus"));
        panel.add(new JButton("Keluar"));
        return panel;
    }
}

BoxLayout mengatur satu sumbu dan menyediakan filler untuk mendorong komponen. Box.createHorizontalGlue() adalah ruang elastis yang menyerap sisa lebar — trik klasik menempel tombol ke kanan:

java PanelBox.java — BoxLayout dengan perekat horizontal
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JPanel;

public class PanelBox {
    public static JPanel bangun() {
        JPanel panel = new JPanel();
        panel.setLayout(new javax.swing.BoxLayout(panel, javax.swing.BoxLayout.X_AXIS));
        panel.add(new JButton("Bantuan"));
        panel.add(Box.createHorizontalGlue()); // ruang elastis
        panel.add(new JButton("Simpan"));
        panel.add(Box.createHorizontalStrut(8)); // jarak tetap 8 piksel
        panel.add(new JButton("Batal"));
        return panel;
    }
}

GridBagLayout adalah yang paling kaya — dan paling banyak ditakuti pemula karena satu-satunya yang mengatur letak lewat objek kendali GridBagConstraints. Kendali tersebut menyatakan sel address (gridx, gridy), seberapa banyak sel diduduki (gridwidth), dan bagaimana komponen meregang (fill):

java PanelForm.java — GridBagLayout untuk formulir
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class PanelForm {
    public static JPanel bangun() {
        JPanel panel = new JPanel(new GridBagLayout());
        GridBagConstraints k = new GridBagConstraints();
        k.insets = new Insets(4, 4, 4, 4);
        k.anchor = GridBagConstraints.LINE_END;
        k.gridx = 0; k.gridy = 0;
        panel.add(new JLabel("Nama:"), k);
        k.gridx = 1; k.gridy = 0;
        k.fill = GridBagConstraints.HORIZONTAL;
        k.weightx = 1.0; // kolom input menyerap sisa lebar
        panel.add(new JTextField("Budi", 16), k);
        k.gridx = 0; k.gridy = 1; k.fill = GridBagConstraints.NONE;
        panel.add(new JLabel("Kelas:"), k);
        k.gridx = 1; k.gridy = 1; k.fill = GridBagConstraints.HORIZONTAL;
        panel.add(new JTextField("11-A", 16), k);
        return panel;
    }
}

Nilai weightx = 1.0 pada kolom input adalah kunci: saat jendela melebar, seluruh lebar tambahan mengalir ke kolom itu, sementara kolom label tetap sempit.

Simulasi GridLayout Tanpa Layar #

GridLayout paling mudah dibedah karena aritmetikanya terbuka: lebar sel = (lebar panel − total celah horizontal) ÷ jumlah kolom. Program berikut membangun grid 2×3 bercelah 5 piksel, memberi panel ukuran tetap 160×90, lalu membaca koordinat hasil tata:

java TataGrid.java
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JPanel;

/** Mensimulasikan GridLayout: sel sama besar, terisi kiri ke kanan. */
public class TataGrid {
    public static void main(String[] args) {
        JPanel panel = new JPanel(new GridLayout(2, 3, 5, 5));
        String[] nama = { "A", "B", "C", "D", "E", "F" };
        for (String n : nama) {
            panel.add(new JButton(n));
        }
        panel.setSize(160, 90); // ukuran panel tetap, bukan hasil ukur font
        panel.doLayout();       // paksa layout manager bekerja sekarang

        for (int i = 0; i < panel.getComponentCount(); i++) {
            var c = panel.getComponent(i);
            System.out.printf("%s -> x=%d y=%d lebar=%d tinggi=%d%n",
                    nama[i], c.getX(), c.getY(), c.getWidth(), c.getHeight());
        }
    }
}

Output yang Dihasilkan:

text
A -> x=0 y=0 lebar=50 tinggi=42
B -> x=55 y=0 lebar=50 tinggi=42
C -> x=110 y=0 lebar=50 tinggi=42
D -> x=0 y=47 lebar=50 tinggi=42
E -> x=55 y=47 lebar=50 tinggi=42
F -> x=110 y=47 lebar=50 tinggi=42

Mari kita cocokkan angka dengan rumusnya:

  1. Baris 7 (new GridLayout(2, 3, 5, 5)): dua baris, tiga kolom, celah horizontal 5 piksel, celah vertikal 5 piksel. Enam tombol menempati keenam sel secara berurutan.
  2. Baris 13-14 (setSize + doLayout): setSize menetapkan ukuran container; doLayout memaksa layout manager membagikan area itu kepada anak-anak sekarang juga, tanpa menunggu jendela nyata.
  3. Lebar sel = (160 − 2×5) ÷ 3 = 50: terlihat pada keluaran — setiap tombol berlebar tepat 50. Posisi x tombol B adalah 50+5 = 55, dan C di 110: pola +55 per kolom.
  4. Tinggi sel = (90 − 5) ÷ 2 = 42,5 → 42: pembagian bulat menghasilkan 42; baris kedua mulai di y = 42+5 = 47, persis seperti keluaran tombol D.

Wilayah BorderLayout #

BorderLayout memakai logikanya sendiri: NORTH dan SOUTH diukur sesuai tinggi pilihan lalu merentang selebar panel; EAST dan WEST diukur sesuai lebar pilihan; CENTER menyerap seluruh sisa ruang. Program berikut memverifikasi pembagian tersebut pada panel 200×120:

java TataBorder.java
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JPanel;

/** Mensimulasikan BorderLayout: lima wilayah dengan prioritas ukuran berbeda. */
public class TataBorder {
    static JButton tombol(String teks, int tinggiPilihan) {
        JButton b = new JButton(teks);
        b.setPreferredSize(new Dimension(60, tinggiPilihan));
        return b;
    }

    public static void main(String[] args) {
        JPanel panel = new JPanel(new BorderLayout(4, 4));
        panel.add(tombol("Utara", 30), BorderLayout.NORTH);
        panel.add(tombol("Barat", 0), BorderLayout.WEST);
        panel.add(tombol("Tengah", 0), BorderLayout.CENTER);
        panel.add(tombol("Timur", 0), BorderLayout.EAST);
        panel.add(tombol("Selatan", 30), BorderLayout.SOUTH);

        panel.setSize(200, 120);
        panel.doLayout();

        String[] wilayah = { "Utara", "Barat", "Tengah", "Timur", "Selatan" };
        for (int i = 0; i < wilayah.length; i++) {
            var c = panel.getComponent(i);
            System.out.printf("%-7s -> x=%d y=%d lebar=%d tinggi=%d%n",
                    wilayah[i], c.getX(), c.getY(), c.getWidth(), c.getHeight());
        }
    }
}

Output yang Dihasilkan:

text
Utara   -> x=0 y=0 lebar=200 tinggi=30
Barat   -> x=0 y=34 lebar=60 tinggi=52
Tengah  -> x=64 y=34 lebar=72 tinggi=52
Timur   -> x=140 y=34 lebar=60 tinggi=52
Selatan -> x=0 y=90 lebar=200 tinggi=30

Keluaran tersebut membuktikan tiga aturan kerja BorderLayout. Pertama, Utara dan Selatan memang tinggi tepat 30 (ukuran pilihan yang kita setel) namun selebar 200 — wilayah horizontal selalu merentang penuh. Kedua, Barat dan Timur berlebar tepat 60, sedangkan tingginya 52 = 120 − 30 − 30 − 2×4 (celah vertikal 4 piksel dua kali). Ketiga, Tengah menyerap sisa: lebar 72 = 200 − 60 − 60 − 8, posisi x = 64. Jika tidak ada komponen di satu wilayah, wilayah itu bubar dan CENTER makin luas — sifat yang membuat BorderLayout pas sebagai kerangka luar aplikasi.

Komponen sudah bisa ditaruh rapi; kini antarmuka kita masih bisu karena belum ada kode yang bergerak saat tombol ditekan. Chapter berikutnya membuka dunia event-driven programming: listener, sumber kejadian, dan cara Swing mengantarkan klik pengguna ke method kita.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

TataBorder.java

Unduh berkas
java
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JPanel;

/** Mensimulasikan BorderLayout: lima wilayah dengan prioritas ukuran berbeda. */
public class TataBorder {
    static JButton tombol(String teks, int tinggiPilihan) {
        JButton b = new JButton(teks);
        b.setPreferredSize(new Dimension(60, tinggiPilihan));
        return b;
    }

    public static void main(String[] args) {
        JPanel panel = new JPanel(new BorderLayout(4, 4));
        panel.add(tombol("Utara", 30), BorderLayout.NORTH);
        panel.add(tombol("Barat", 0), BorderLayout.WEST);
        panel.add(tombol("Tengah", 0), BorderLayout.CENTER);
        panel.add(tombol("Timur", 0), BorderLayout.EAST);
        panel.add(tombol("Selatan", 30), BorderLayout.SOUTH);

        panel.setSize(200, 120);
        panel.doLayout();

        String[] wilayah = { "Utara", "Barat", "Tengah", "Timur", "Selatan" };
        for (int i = 0; i < wilayah.length; i++) {
            var c = panel.getComponent(i);
            System.out.printf("%-7s -> x=%d y=%d lebar=%d tinggi=%d%n",
                    wilayah[i], c.getX(), c.getY(), c.getWidth(), c.getHeight());
        }
    }
}

TataGrid.java

Unduh berkas
java
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JPanel;

/** Mensimulasikan GridLayout: sel sama besar, terisi kiri ke kanan. */
public class TataGrid {
    public static void main(String[] args) {
        JPanel panel = new JPanel(new GridLayout(2, 3, 5, 5));
        String[] nama = { "A", "B", "C", "D", "E", "F" };
        for (String n : nama) {
            panel.add(new JButton(n));
        }
        panel.setSize(160, 90); // ukuran panel tetap, bukan hasil ukur font
        panel.doLayout();       // paksa layout manager bekerja sekarang

        for (int i = 0; i < panel.getComponentCount(); i++) {
            var c = panel.getComponent(i);
            System.out.printf("%s -> x=%d y=%d lebar=%d tinggi=%d%n",
                    nama[i], c.getX(), c.getY(), c.getWidth(), c.getHeight());
        }
    }
}