Membuat JButton khusus di Java

97

Apakah ada cara untuk membuat JButtondengan gambar tombol Anda sendiri dan tidak hanya dengan gambar di dalam tombol?

Jika tidak, apakah ada cara lain untuk membuat custom JButtondi java?

Anton
sumber

Jawaban:

91

Ketika saya pertama kali belajar Java, kami harus membuat Yahtzee dan saya pikir akan sangat keren untuk membuat komponen dan wadah Swing khusus daripada hanya menggambar semuanya di satu JPanel. Manfaat memperluas Swingkomponen, tentu saja, adalah memiliki kemampuan untuk menambahkan dukungan untuk pintasan keyboard dan fitur aksesibilitas lainnya yang tidak dapat Anda lakukan hanya dengan paint()metode mencetak gambar yang cantik. Namun ini mungkin tidak dilakukan dengan cara terbaik, tetapi ini mungkin titik awal yang baik untuk Anda.

Edit 8/6 - Jika tidak terlihat dari gambar, setiap Die adalah tombol yang dapat Anda klik. Ini akan memindahkannya ke DiceContainerbawah. Melihat kode sumber Anda dapat melihat bahwa setiap tombol Die digambar secara dinamis, berdasarkan nilainya.

teks alt
teks alt
teks alt

Berikut langkah-langkah dasarnya:

  1. Buat kelas yang diperluas JComponent
  2. Panggil konstruktor induk super()di konstruktor Anda
  3. Pastikan Anda mengimplementasikan kelas MouseListener
  4. Letakkan ini di konstruktor:

    enableInputMethods(true);   
    addMouseListener(this);
  5. Ganti metode ini:

    public Dimension getPreferredSize()  
    public Dimension getMinimumSize()  
    public Dimension getMaximumSize()
  6. Ganti metode ini:

    public void paintComponent(Graphics g)

Jumlah ruang yang harus Anda kerjakan saat menggambar tombol Anda ditentukan oleh getPreferredSize(), dengan asumsi getMinimumSize()dan getMaximumSize()mengembalikan nilai yang sama. Saya belum banyak bereksperimen dengan ini, tetapi, tergantung pada tata letak yang Anda gunakan untuk GUI, tombol Anda dapat terlihat sangat berbeda.

Dan terakhir, kode sumber . Seandainya saya melewatkan sesuatu.

Kevin
sumber
1
Hai, terima kasih pertama untuk kodenya! Saya menyarankan untuk menambahkan 'setActionComme (String Command)' ke kode Anda. ini adalah salah satu cara untuk memfilter acara di Swing. (tetapi kemudian Anda dapat membantah bahwa ada 1001 hal yang dapat ditambahkan untuk membuat segalanya sedikit lebih baik: P)
Jason Rogers
1
Untuk membuat dadu yang dapat Anda tekan, Anda sebenarnya dapat menggunakan JButton lama biasa (daripada membuat subkelas atau membuat JComponent kustom) dengan memanfaatkan setIcon / setPressedIcon serta fungsionalitas Ikon lainnya di JButton
ControlAltDel
34

Ya, ini mungkin. Salah satu kelebihan utama dalam menggunakan Swing adalah kemudahan pembuatan dan manipulasi kontrol abstrak.

Berikut adalah cara cepat dan kotor untuk memperluas kelas JButton yang ada untuk menggambar lingkaran di sebelah kanan teks.

package test;

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;

import javax.swing.JButton;
import javax.swing.JFrame;

public class MyButton extends JButton {

    private static final long serialVersionUID = 1L;

    private Color circleColor = Color.BLACK;

    public MyButton(String label) {
        super(label);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Dimension originalSize = super.getPreferredSize();
        int gap = (int) (originalSize.height * 0.2);
        int x = originalSize.width + gap;
        int y = gap;
        int diameter = originalSize.height - (gap * 2);

        g.setColor(circleColor);
        g.fillOval(x, y, diameter, diameter);
    }

    @Override
    public Dimension getPreferredSize() {
        Dimension size = super.getPreferredSize();
        size.width += size.height;
        return size;
    }

    /*Test the button*/
    public static void main(String[] args) {
        MyButton button = new MyButton("Hello, World!");

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 400);

        Container contentPane = frame.getContentPane();
        contentPane.setLayout(new FlowLayout());
        contentPane.add(button);

        frame.setVisible(true);
    }

}

Perhatikan bahwa dengan mengganti paintComponent , konten tombol bisa diubah, tetapi batasnya dicat dengan metode paintBorder . The getPreferredSize metode juga perlu dikelola untuk mendukung perubahan secara dinamis dengan konten. Perhatian harus diberikan saat mengukur metrik font dan dimensi gambar.

Untuk membuat kontrol yang dapat Anda andalkan, kode di atas bukanlah pendekatan yang benar. Dimensi dan warna dinamis di Ayunan dan bergantung pada tampilan dan nuansa yang digunakan. Bahkan tampilan Metal default telah berubah di semua versi JRE. Akan lebih baik untuk mengimplementasikan AbstractButton dan menyesuaikan dengan pedoman yang ditetapkan oleh Swing API. Sebuah titik awal yang baik adalah dengan melihat kelas javax.swing.LookAndFeel dan javax.swing.UIManager .

http://docs.oracle.com/javase/8/docs/api/javax/swing/LookAndFeel.html

http://docs.oracle.com/javase/8/docs/api/javax/swing/UIManager.html

Memahami anatomi LookAndFeel berguna untuk kontrol penulisan: Membuat Tampilan dan Nuansa Kustom

McDowell
sumber
13

Anda selalu dapat mencoba tampilan & nuansa Synth. Anda menyediakan file xml yang berfungsi sebagai semacam lembar gaya, bersama dengan gambar yang ingin Anda gunakan. Kode tersebut mungkin terlihat seperti ini:

try {
    SynthLookAndFeel synth = new SynthLookAndFeel();
    Class aClass = MainFrame.class;
    InputStream stream = aClass.getResourceAsStream("\\default.xml");

    if (stream == null) {
        System.err.println("Missing configuration file");
        System.exit(-1);                
    }

    synth.load(stream, aClass);

    UIManager.setLookAndFeel(synth);
} catch (ParseException pe) {
    System.err.println("Bad configuration file");
    pe.printStackTrace();
    System.exit(-2);
} catch (UnsupportedLookAndFeelException ulfe) {
    System.err.println("Old JRE in use. Get a new one");
    System.exit(-3);
}

Dari sana, lanjutkan dan tambahkan JButton Anda seperti biasa. Satu-satunya perubahan adalah Anda menggunakan metode setName (string) untuk mengidentifikasi ke mana tombol harus dipetakan dalam file xml.

File xml mungkin terlihat seperti ini:

<synth>
    <style id="button">
        <font name="DIALOG" size="12" style="BOLD"/>
        <state value="MOUSE_OVER">
            <imagePainter method="buttonBackground" path="dirt.png" sourceInsets="2 2 2 2"/>
            <insets top="2" botton="2" right="2" left="2"/>
        </state>
        <state value="ENABLED">
            <imagePainter method="buttonBackground" path="dirt.png" sourceInsets="2 2 2 2"/>
            <insets top="2" botton="2" right="2" left="2"/>
        </state>
    </style>
    <bind style="button" type="name" key="dirt"/>
</synth>

Elemen bind di sana menentukan apa yang akan dipetakan (dalam contoh ini, ini akan menerapkan gaya itu ke tombol apa pun yang properti namanya telah disetel ke "kotoran").

Dan beberapa tautan berguna:

http://javadesktop.org/articles/synth/

http://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/synth.html

rjohnston
sumber
8

Saya mungkin pergi sejuta mil ke arah yang salah (tapi saya hanya muda: P). tetapi Anda tidak dapat menambahkan grafik ke panel dan kemudian pendengar mouse ke objek grafik sehingga ketika pengguna pada grafik tindakan Anda dilakukan sebelumnya.

AngelOfCake
sumber
1
Ini akan berhasil, tetapi saya lebih suka menggunakan JButton standar daripada membuat jenis tombol saya jika memungkinkan.
Anton
7

Saya belum melakukan pengembangan SWING sejak kelas CS awal saya, tetapi jika itu tidak dibangun, Anda bisa mewarisi javax.swing.AbstractButtondan membuatnya sendiri. Harus cukup sederhana untuk menghubungkan sesuatu dengan kerangka yang ada.

John Downey
sumber