Creazione di un JButton personalizzato in Java


97

C'è un modo per creare un'immagine JButtoncon il proprio pulsante e non solo con un'immagine all'interno del pulsante?

In caso contrario, c'è un altro modo per creare un custom JButtonin java?

Risposte:


91

Quando stavo imparando Java per la prima volta, dovevamo creare Yahtzee e ho pensato che sarebbe stato interessante creare componenti e contenitori Swing personalizzati invece di disegnare tutto su uno JPanel. Il vantaggio di estendere i Swingcomponenti, ovviamente, è avere la possibilità di aggiungere il supporto per le scorciatoie da tastiera e altre funzionalità di accessibilità che non puoi fare semplicemente facendo in modo che un paint()metodo stampi una bella immagine. Tuttavia, potrebbe non essere fatto nel modo migliore, ma potrebbe essere un buon punto di partenza per te.

Modifica 8/6 - Se non era evidente dalle immagini, ogni dado è un pulsante su cui puoi fare clic. Questo lo sposterà in DiceContainerbasso. Guardando il codice sorgente puoi vedere che ogni pulsante Die viene disegnato dinamicamente, in base al suo valore.

testo alternativo
testo alternativo
testo alternativo

Ecco i passaggi di base:

  1. Crea una classe che si estende JComponent
  2. Chiama il costruttore genitore super()nei tuoi costruttori
  3. Assicurati di classe attrezzi MouseListener
  4. Mettilo nel costruttore:

    enableInputMethods(true);   
    addMouseListener(this);
    
  5. Ignora questi metodi:

    public Dimension getPreferredSize()  
    public Dimension getMinimumSize()  
    public Dimension getMaximumSize()
    
  6. Sostituisci questo metodo:

    public void paintComponent(Graphics g)

La quantità di spazio con cui devi lavorare quando disegni il tuo pulsante è definita da getPreferredSize(), assumendo getMinimumSize()e getMaximumSize()restituendo lo stesso valore. Non ho sperimentato molto con questo ma, a seconda del layout che usi per la tua GUI, il tuo pulsante potrebbe apparire completamente diverso.

E infine, il codice sorgente . Nel caso mi sia perso qualcosa.


1
Ciao, prima grazie per il codice! Suggerirei di aggiungere un "setActionComme (String Command)" al codice. è uno dei modi per filtrare gli eventi in Swing. (ma poi puoi sostenere che ci sono 1001 cose che potrebbero essere aggiunte per migliorare leggermente le cose: P)
Jason Rogers

1
Per creare un dado che puoi premere, puoi effettivamente utilizzare un semplice vecchio JButton (piuttosto che sottoclassare o creare un JComponent personalizzato) sfruttando setIcon / setPressedIcon e altre funzionalità dell'icona in JButton
ControlAltDel

34

Sì, è possibile. Uno dei principali vantaggi dell'utilizzo di Swing è la facilità con cui i controlli astratti possono essere creati e manipolati.

Ecco un modo rapido e sporco per estendere la classe JButton esistente per disegnare un cerchio a destra del testo.

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);
    }

}

Notare che sovrascrivendo paintComponent che il contenuto del pulsante può essere modificato, ma che il bordo è disegnato dal metodo paintBorder . Anche il metodo getPreferredSize deve essere gestito per supportare dinamicamente le modifiche al contenuto. È necessario prestare attenzione quando si misurano le metriche dei caratteri e le dimensioni dell'immagine.

Per creare un controllo su cui puoi fare affidamento, il codice precedente non è l'approccio corretto. Dimensioni e colori sono dinamici in Swing e dipendono dall'aspetto e dalla sensazione utilizzati. Anche l' aspetto Metal predefinito è cambiato nelle versioni di JRE. Sarebbe meglio implementare AbstractButton e conformarsi alle linee guida stabilite dall'API Swing. Un buon punto di partenza è guardare le classi javax.swing.LookAndFeel e 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

Comprendere l'anatomia di LookAndFeel è utile per scrivere i controlli: Creazione di un aspetto personalizzato


13

Puoi sempre provare il look & feel del Synth. Fornisci un file xml che funge da una sorta di foglio di stile, insieme a tutte le immagini che desideri utilizzare. Il codice potrebbe essere simile a questo:

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);
}

Da lì, vai avanti e aggiungi il tuo JButton come faresti normalmente. L'unico cambiamento è che si utilizza il metodo setName (stringa) per identificare a cosa deve mappare il pulsante nel file xml.

Il file xml potrebbe essere simile a questo:

<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>

L'elemento bind qui specifica a cosa mappare (in questo esempio, applicherà quello stile a tutti i pulsanti la cui proprietà name è stata impostata su "dirt").

E un paio di link utili:

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

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


8

Probabilmente sto andando un milione di miglia nella direzione sbagliata (ma sono solo giovane: P). ma non potresti aggiungere la grafica a un pannello e poi un mouselistener all'oggetto grafico in modo che quando l'utente sul grafico la tua azione sia eseguita.


1
Questo funzionerebbe, ma preferirei utilizzare il JButton standard piuttosto che creare un mio tipo di pulsante, se possibile.
Anton

7

Non ho sviluppato SWING dai miei primi corsi CS, ma se non fosse stato integrato potresti semplicemente ereditare javax.swing.AbstractButtone creare il tuo. Dovrebbe essere abbastanza semplice collegare qualcosa insieme al loro framework esistente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.