Створення користувацького JButton в Java


97

Чи є спосіб створити JButtonграфіку за допомогою власної кнопки, а не лише за допомогою зображення всередині кнопки?

Якщо ні, чи є інший спосіб створити власний JButtonв Java?

Відповіді:


91

Коли я вперше вивчав Java, нам потрібно було зробити Yahtzee, і я подумав, що було б круто створювати власні компоненти та контейнери Swing, а не просто малювати все на одному JPanel. Звичайно, перевага розширення Swingкомпонентів полягає в можливості додавати підтримку комбінацій клавіш та інші функції доступності, що неможливо зробити, лише якщо paint()метод друкує гарне зображення. Однак це може бути зроблено не найкращим чином, але це може бути хорошою відправною точкою для вас.

Редагувати 8/6 - Якщо це не було видно із зображень, кожна плашка - це кнопка, яку ви можете натиснути. Це перемістить його DiceContainerнижче. Переглядаючи вихідний код, ви можете побачити, що кожна кнопка Die накреслюється динамічно на основі її значення.

alt текст
alt текст
alt текст

Ось основні кроки:

  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()повертаючи одне і те ж значення. Я не надто експериментував із цим, але, залежно від макета, який ви використовуєте для графічного інтерфейсу, ваша кнопка може виглядати зовсім по-іншому.

І, нарешті, вихідний код . На випадок, якщо я щось пропустив.


1
Привіт, спочатку дякую за код! Я б запропонував додати 'setActionComme (String Command)' до вашого коду. це один із способів фільтрувати події в Swing. (але тоді ви можете стверджувати, що можна додати 1001 річ, яка покращить ситуацію: P)
Джейсон Роджерс

1
Щоб створити матрицю, яку ви можете натиснути, ви можете фактично використовувати звичайний старий JButton (а не підкласувати або створювати власний JComponent), скориставшись перевагами setIcon / setPressIcon, а також іншими функціональними можливостями піктограми в JButton
ControlAltDel

34

Так, це можливо. Одним з основних плюсів використання 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 і залежать від зовнішнього вигляду та відчуття, що використовується. Навіть металевий вигляд за замовчуванням змінився в різних версіях 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 корисно для написання елементів керування: Створення власного вигляду та відчуття


13

Ви завжди можете спробувати 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 (рядок), щоб визначити, до чого повинна відповідати кнопка у файлі 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>

Елемент прив'язки вказує, на що відображати карту (у цьому прикладі він застосовуватиме цей стиль до будь-яких кнопок, властивість імені яких має значення "бруд").

І ще пару корисних посилань:

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

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


8

Я, мабуть, проїжджаю мільйон миль у неправильному прямому напрямку (але я тільки молодий: P). але ви не могли додати графіку до панелі, а потім мультісенератор до графічного об'єкта, щоб, коли користувач на графіці виконав вашу дію.


1
Це могло б спрацювати, але я б віддав перевагу використанню стандартного JButton, ніж створенню кнопки типу мого типу, якщо це можливо.
Антон

7

Я не займався розробкою SWING з моїх початкових класів CS, але якби він не був вбудований, ви могли б просто успадкувати javax.swing.AbstractButtonта створити свій власний. Повинно бути досить просто з'єднати щось разом із існуючим фреймворком.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.