Tạo một JButton tùy chỉnh trong Java


97

Có cách nào để tạo một JButtonhình ảnh nút của riêng bạn chứ không chỉ bằng một hình ảnh bên trong nút không?

Nếu không, có cách nào khác để tạo tùy chỉnh JButtontrong java không?

Câu trả lời:


91

Khi tôi lần đầu tiên học Java, chúng tôi phải tạo ra Yahtzee và tôi nghĩ sẽ rất tuyệt khi tạo các thành phần và vùng chứa Swing tùy chỉnh thay vì chỉ vẽ mọi thứ trên một JPanel. Tất nhiên, lợi ích của việc mở rộng Swingcác thành phần là có khả năng thêm hỗ trợ cho các phím tắt và các tính năng trợ năng khác mà bạn không thể thực hiện chỉ bằng cách paint()in một bức tranh đẹp. Tuy nhiên, nó có thể không được thực hiện theo cách tốt nhất, nhưng nó có thể là một điểm khởi đầu tốt cho bạn.

Chỉnh sửa 8/6 - Nếu nó không rõ ràng từ hình ảnh, mỗi Die là một nút bạn có thể nhấp vào. Thao tác này sẽ chuyển nó xuống DiceContainerbên dưới. Nhìn vào mã nguồn, bạn có thể thấy rằng mỗi nút Die được vẽ động, dựa trên giá trị của nó.

văn bản thay thế
văn bản thay thế
văn bản thay thế

Dưới đây là các bước cơ bản:

  1. Tạo một lớp học mở rộng JComponent
  2. Gọi hàm tạo cha super()trong các hàm tạo của bạn
  3. Đảm bảo lớp bạn triển khai MouseListener
  4. Đặt cái này trong hàm tạo:

    enableInputMethods(true);   
    addMouseListener(this);
    
  5. Ghi đè các phương thức này:

    public Dimension getPreferredSize()  
    public Dimension getMinimumSize()  
    public Dimension getMaximumSize()
    
  6. Ghi đè phương thức này:

    public void paintComponent(Graphics g)

Khoảng không gian bạn phải làm việc khi vẽ nút của bạn được xác định bởi getPreferredSize(), giả sử getMinimumSize()getMaximumSize()trả về cùng một giá trị. Tôi chưa thử nghiệm quá nhiều với điều này nhưng, tùy thuộc vào bố cục bạn sử dụng cho GUI của mình mà nút của bạn có thể trông hoàn toàn khác.

Và cuối cùng là mã nguồn . Trong trường hợp tôi bỏ lỡ bất cứ điều gì.


1
Xin chào, đầu tiên cảm ơn vì mã! Tôi đề nghị thêm 'setActionComme (Chuỗi lệnh)' vào mã của bạn. nó là một trong những cách để lọc các sự kiện trong Swing. (nhưng sau đó bạn có thể tranh luận rằng có là 1001 điều có thể được thêm vào làm cho mọi việc tốt hơn một chút: P)
Jason Rogers

1
Để tạo một chết mà bạn có thể nhấn, bạn thực sự có thể sử dụng một đồng bằng cũ JButton (chứ không phải subclassing hoặc tạo ra một tùy chỉnh JComponent) bằng cách tận dụng các setIcon / setPressedIcon cũng như chức năng Biểu tượng khác trong JButton
ControlAltDel

34

Có, điều này là có thể. Một trong những ưu điểm chính của việc sử dụng Swing là dễ dàng tạo và thao tác các điều khiển trừu tượng.

Đây là một cách nhanh chóng và tiện lợi để mở rộng lớp JButton hiện có để vẽ một vòng tròn ở bên phải văn bản.

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

}

Lưu ý rằng bằng cách ghi đè paintComponent rằng nội dung của nút có thể được thay đổi, nhưng đường viền được vẽ bằng phương thức paintBorder . Các getPreferredSize phương pháp cũng cần phải được quản lý để thay đổi sự ủng hộ động đến nội dung. Cần phải cẩn thận khi đo số liệu phông chữ và kích thước hình ảnh.

Để tạo điều khiển mà bạn có thể dựa vào, đoạn mã trên không phải là cách tiếp cận chính xác. Kích thước và màu sắc linh hoạt trong Swing và phụ thuộc vào giao diện được sử dụng. Ngay cả giao diện Kim loại mặc định cũng đã thay đổi trên các phiên bản JRE. Sẽ tốt hơn nếu triển khai AbstractButton và tuân thủ các nguyên tắc do API Swing đưa ra. Một điểm khởi đầu tốt là xem xét các lớp javax.swing.LookAndFeeljavax.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

Hiểu cấu trúc của LookAndFeel rất hữu ích cho việc viết các điều khiển: Tạo Giao diện và Cảm nhận Tùy chỉnh


13

Bạn luôn có thể thử giao diện Synth. Bạn cung cấp tệp xml hoạt động như một loại biểu định kiểu, cùng với bất kỳ hình ảnh nào bạn muốn sử dụng. Mã có thể trông như thế này:

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

Từ đó, hãy tiếp tục và thêm JButton của bạn như bạn thường làm. Thay đổi duy nhất là bạn sử dụng phương thức setName (string) để xác định những gì nút sẽ ánh xạ đến trong tệp xml.

Tệp xml có thể trông giống như sau:

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

Phần tử liên kết ở đó chỉ định những gì sẽ ánh xạ tới (trong ví dụ này, nó sẽ áp dụng kiểu đó cho bất kỳ nút nào có thuộc tính tên đã được đặt thành "dơ").

Và một số liên kết hữu ích:

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

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


8

Tôi có lẽ sẽ là một triệu dặm trong sai trực tiếp (nhưng tôi chỉ trẻ: P). nhưng bạn không thể thêm đồ họa vào bảng điều khiển và sau đó là một mouselistener vào đối tượng đồ họa để khi người dùng trên đồ họa hành động của bạn được định dạng trước.


1
Điều này sẽ hiệu quả, nhưng tôi muốn sử dụng JButton tiêu chuẩn hơn là tạo một loại nút của tôi nếu có thể.
Anton

7

Tôi đã không thực hiện phát triển SWING kể từ các lớp CS đầu tiên của mình nhưng nếu nó không được tích hợp sẵn, bạn có thể kế thừa javax.swing.AbstractButtonvà tạo của riêng mình. Sẽ khá đơn giản để kết nối một cái gì đó với nhau với khuôn khổ hiện có của chúng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.