Создание собственного JButton в Java - PullRequest
90 голосов
/ 05 августа 2008

Есть ли способ создать JButton с вашей собственной графикой кнопки, а не только с изображением внутри кнопки?

Если нет, есть ли другой способ создать пользовательский JButton в Java?

Ответы [ 5 ]

87 голосов
/ 05 августа 2008

Когда я впервые изучал Java, нам пришлось создать Yahtzee, и я подумал, что было бы здорово создавать собственные компоненты и контейнеры Swing вместо того, чтобы просто рисовать все на одном JPanel. Преимущество расширения Swing компонентов, конечно же, заключается в возможности добавлять поддержку сочетаний клавиш и других специальных возможностей, которые вы не можете сделать, просто используя метод paint() для печати симпатичной картинки. Это может быть сделано не лучшим образом, но может стать хорошей отправной точкой для вас.

Редактировать 8/6 - Если это не было видно из изображений, каждый кубик - это кнопка, которую вы можете нажать. Это переместит его на DiceContainer ниже. Глядя на исходный код, вы можете видеть, что каждая кнопка Die рисуется динамически в зависимости от ее значения.

alt text
alt text
alt text

Вот основные шаги:

  1. Создать класс, который расширяет JComponent
  2. Вызовите родительский конструктор super() в ваших конструкторах
  3. Убедитесь, что вы реализуете класс MouseListener
  4. Поместите это в конструктор:

    enableInputMethods(true);   
    addMouseListener(this);
    
  5. Переопределить эти методы:

    public Dimension getPreferredSize()  
    public Dimension getMinimumSize()  
    public Dimension getMaximumSize()
    
  6. Переопределить этот метод:

    public void paintComponent(Graphics g)
    

Объем пространства, с которым вам нужно работать при рисовании кнопки, определяется как getPreferredSize(), при условии, что getMinimumSize() и getMaximumSize() возвращают одно и то же значение. Я не слишком много экспериментировал с этим, но в зависимости от макета, который вы используете для своего графического интерфейса, ваша кнопка может выглядеть совершенно иначе.

И, наконец, исходный код . На случай, если я что-то пропустил.

32 голосов
/ 05 августа 2008

Да, это возможно. Одним из главных плюсов использования Swing является простота создания и управления абстрактными элементами управления.

Вот быстрый и грязный способ расширить существующий класс JButton, чтобы нарисовать круг справа от текста.

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

}

Обратите внимание, что при переопределении paintComponent содержимое кнопки может быть изменено, но граница окрашена методом paintBorder . Метод getPreferredSize также необходимо управлять, чтобы динамически поддерживать изменения содержимого. Необходимо соблюдать осторожность при измерении метрики шрифта и размеров изображения.

Для создания элемента управления, на который можно положиться, приведенный выше код не является правильным подходом. Размеры и цвета в Swing динамичны и зависят от внешнего вида и ощущений, которые используются. Даже внешний вид Metal по умолчанию изменился во всех версиях JRE. Было бы лучше реализовать AbstractButton и соответствовать рекомендациям, установленным Swing API. Хорошей отправной точкой является рассмотрение классов javax.swing.LookAndFeel и 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

Понимание анатомии LookAndFeel полезно для написания элементов управления: Создание собственного внешнего вида

12 голосов
/ 05 августа 2008

Вы всегда можете попробовать Synth look & feel. Вы предоставляете XML-файл, который действует как своего рода таблицу стилей вместе с любыми изображениями, которые вы хотите использовать. Код может выглядеть так:

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

Оттуда иди и добавь свой JButton, как обычно. Единственное изменение заключается в том, что вы используете метод setName (string), чтобы определить, к чему должна быть привязана кнопка в XML-файле.

XML-файл может выглядеть следующим образом:

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

Элемент bind там указывает, что сопоставить (в этом примере он будет применять этот стиль ко всем кнопкам, для свойства name которых установлено значение «dirt»).

И пара полезных ссылок:

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

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

8 голосов
/ 20 августа 2008

Я, вероятно, пройду миллион миль по неправильному маршруту (но я всего лишь молод: P). но вы не можете добавить графическое изображение на панель, а затем мышиный слой к графическому объекту, чтобы, когда пользователь на графике выполнял ваши действия.

6 голосов
/ 05 августа 2008

Я не занимался разработкой SWING с ранних классов CS, но если он не был встроен, вы могли бы просто наследовать javax.swing.AbstractButton и создавать свои собственные. Должно быть довольно просто соединить что-то с существующей структурой.

...