Erstellen eines benutzerdefinierten JButton in Java

97

Gibt es eine Möglichkeit, eine JButtonmit Ihrer eigenen Schaltflächengrafik zu erstellen und nicht nur mit einem Bild innerhalb der Schaltfläche?

Wenn nicht, gibt es eine andere Möglichkeit, eine benutzerdefinierte JButtonVersion in Java zu erstellen ?

Anton
quelle

Antworten:

91

Als ich Java zum ersten Mal lernte, mussten wir Yahtzee erstellen und ich dachte, es wäre cool, benutzerdefinierte Swing-Komponenten und -Container zu erstellen, anstatt nur alles auf einen zu zeichnen JPanel. Der Vorteil der Erweiterung von SwingKomponenten besteht natürlich darin, dass Tastaturkürzel und andere Eingabehilfen unterstützt werden können, die Sie nicht einfach durch paint()Drucken eines hübschen Bilds durch eine Methode ausführen können. Es kann jedoch nicht der beste Weg sein, aber es kann ein guter Ausgangspunkt für Sie sein.

Bearbeiten 8/6 - Wenn dies aus den Bildern nicht ersichtlich ist, ist jeder Würfel eine Schaltfläche, auf die Sie klicken können. Dadurch wird es nach DiceContainerunten verschoben . Wenn Sie sich den Quellcode ansehen, sehen Sie, dass jede Die-Schaltfläche basierend auf ihrem Wert dynamisch gezeichnet wird.

Alt-Text
Alt-Text
Alt-Text

Hier sind die grundlegenden Schritte:

  1. Erstellen Sie eine Klasse, die erweitert wird JComponent
  2. Rufen Sie den übergeordneten Konstruktor super()in Ihren Konstruktoren auf
  3. Stellen Sie sicher, dass Sie Klassengeräte verwenden MouseListener
  4. Geben Sie dies in den Konstruktor ein:

    enableInputMethods(true);   
    addMouseListener(this);
  5. Überschreiben Sie diese Methoden:

    public Dimension getPreferredSize()  
    public Dimension getMinimumSize()  
    public Dimension getMaximumSize()
  6. Überschreiben Sie diese Methode:

    public void paintComponent(Graphics g)

Die Menge an Speicherplatz, mit der Sie beim Zeichnen Ihrer Schaltfläche arbeiten müssen, wird definiert getPreferredSize(), indem derselbe Wert angenommen getMinimumSize()und getMaximumSize()zurückgegeben wird. Ich habe nicht zu viel damit experimentiert, aber je nach dem Layout, das Sie für Ihre GUI verwenden, kann Ihre Schaltfläche völlig anders aussehen.

Und schließlich der Quellcode . Für den Fall, dass ich etwas verpasst habe.

Kevin
quelle
1
Hallo, erstmal danke für den Code! Ich würde vorschlagen, Ihrem Code ein 'setActionComme (String Command)' hinzuzufügen. Dies ist eine der Möglichkeiten, Ereignisse in Swing zu filtern. (aber dann können Sie argumentieren, dass es 1001 Dinge gibt, die hinzugefügt werden könnten, um die Dinge etwas besser zu machen: P)
Jason Rogers
1
Um einen Würfel zu erstellen, den Sie drücken können, können Sie einen einfachen alten JButton verwenden (anstatt eine Unterklasse zu erstellen oder eine benutzerdefinierte JComponent zu erstellen), indem Sie die Funktionen setIcon / setPressedIcon sowie andere Icon-Funktionen in JButton
ControlAltDel vom
34

Ja, das ist möglich. Einer der Hauptprofis für die Verwendung von Swing ist die Leichtigkeit, mit der abstrakte Steuerelemente erstellt und bearbeitet werden können.

Hier ist eine schnelle und schmutzige Möglichkeit, die vorhandene JButton-Klasse zu erweitern, um einen Kreis rechts vom Text zu zeichnen.

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

}

Beachten Sie, dass durch Überschreiben von paintComponent der Inhalt der Schaltfläche geändert werden kann, der Rahmen jedoch mit der paintBorder- Methode gezeichnet wird. Die Methode getPreferredSize muss ebenfalls verwaltet werden, um Änderungen am Inhalt dynamisch zu unterstützen. Bei der Messung von Schriftmetriken und Bildabmessungen ist Vorsicht geboten.

Für die Erstellung eines Steuerelements, auf das Sie sich verlassen können, ist der obige Code nicht der richtige Ansatz. Abmessungen und Farben sind in Swing dynamisch und hängen vom verwendeten Erscheinungsbild ab. Sogar das Standard- Metal- Aussehen hat sich in den JRE-Versionen geändert. Es wäre besser, AbstractButton zu implementieren und die Richtlinien der Swing-API einzuhalten. Ein guter Ausgangspunkt ist ein Blick auf die Klassen javax.swing.LookAndFeel und 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

Das Verständnis der Anatomie von LookAndFeel ist nützlich, um Steuerelemente zu schreiben: Erstellen eines benutzerdefinierten Erscheinungsbilds

McDowell
quelle
13

Sie können immer das Synth Look & Feel ausprobieren. Sie stellen eine XML-Datei bereit, die als eine Art Stylesheet fungiert, sowie alle Bilder, die Sie verwenden möchten. Der Code könnte folgendermaßen aussehen:

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

Von dort aus fügen Sie Ihren JButton wie gewohnt hinzu. Die einzige Änderung besteht darin, dass Sie die Methode setName (Zeichenfolge) verwenden, um zu identifizieren, wem die Schaltfläche in der XML-Datei zugeordnet werden soll.

Die XML-Datei könnte folgendermaßen aussehen:

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

Das dortige Bindungselement gibt an, was zugeordnet werden soll (in diesem Beispiel wird dieses Styling auf alle Schaltflächen angewendet, deren Namenseigenschaft auf "Schmutz" gesetzt wurde).

Und ein paar nützliche Links:

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

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

rjohnston
quelle
8

Ich gehe wahrscheinlich eine Million Meilen in die falsche Richtung (aber ich bin nur jung: P). Sie konnten die Grafik jedoch nicht zu einem Bedienfeld und dann zu einem Mauslistener zum Grafikobjekt hinzufügen, damit Ihre Aktion ausgeführt wird, wenn der Benutzer auf der Grafik ist.

AngelOfCake
quelle
1
Dies würde funktionieren, aber ich würde es vorziehen, den Standard-JButton zu verwenden, als wenn möglich einen Schaltflächentyp zu erstellen.
Anton
7

Ich habe seit meinen frühen CS-Kursen keine SWING-Entwicklung mehr durchgeführt, aber wenn es nicht eingebaut wäre, könnten Sie einfach javax.swing.AbstractButtonIhre eigenen erben und erstellen. Sollte ziemlich einfach sein, etwas mit dem vorhandenen Framework zu verbinden.

John Downey
quelle