在Java中创建一个简单的自定义JComponent?

7

我想在工作项目中开始构建自己定制的JComponent。下面是一个简单的示例,它应该只在屏幕上创建一个球。(我在网上找到了大部分代码),但它提供了一个不错的起点。我的问题是为什么这段代码没有在表单中显示球?我做错了什么?

另外,对于自定义JComponent,应该提供哪些基本方法?

代码:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class testBall {
    public static void main(String[] args) {
        new testBall();
    }

    public testBall() {
        JPanel testPane = new JPanel();
        testPane.setBackground(Color.white);
        testPane.setLayout(new GridBagLayout());
        testPane.add(new MyBall(30,30,10));

        JFrame frame = new JFrame("Testing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(testPane);
        frame.pack();
        frame.setSize(500, 300); 
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

class MyBall extends JComponent
{
    private static final long serialVersionUID = 1L;
    public MyBall() { }
    public MyBall(int x, int y, int diameter)
    {
        super();
        this.setLocation(x, y);
        this.setSize(diameter, diameter);
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.setColor(Color.red);
        g.fillOval(0, 0, 100, 100);
    }
}

我在哪里可以找到JComponent类中应该重写的所有方法列表?(我知道JComponent中应该始终包含某些方法。)

如果我在一个类中创建了此组件的实例并需要更改圆形的颜色,我是否只需从该类调用repaint()方法?

3个回答

6
您正在将MyBall添加到testPane中(它具有GridBagLayout),但没有指定任何约束条件。(也就是说,您的add()调用没有第二个参数。)默认的约束条件很可能不是您想要的。尝试在测试面板中使用BorderLayout,因为它使用BorderLayout.CENTER作为默认值,在您的情况下可能是合理的:
testPane.setLayout(new BorderLayout());

这使得球对我可见。

至于你的第二个问题,我认为你的类定义很好。你要实现的主要方法是paintComponent(),就像你所做的那样。有时需要覆盖get min/max/preferred size方法,但这取决于你想让组件做什么。 JComponent不是抽象的,所以你不必覆盖任何东西。它提供了很多开箱即用的功能,如键盘焦点、可插拔外观、辅助功能等。只要你不想改变这些东西,就将其保持原样。实现paintComponent()和各种get*Size()方法,然后结束它。(你只需要挑选JavaDoc中的方法,看看哪些方法适合覆盖。)

另一种选择是扩展JComponent的子类,如果有一个类与你想要做的事情类似。例如,JPanel通常是实现自己的容器的好起点。

你可能正在寻找比“它取决于”的更具体的内容,但现在,如果你只想画一个球,那么只需覆盖与JComponent的呈现相关的方法(paintCompentent()get*Size()方法)。

顺便说一句,你应该使用SwingUtilities.invokeLater()在Swing线程上创建你的Swing组件。请参见http://docs.oracle.com/javase/6/docs/api/javax/swing/package-summary.html中标题为“Swing的线程策略”的部分。


如果您想要一个包含所有可能或应该包含在JComponent中的方法列表,您会在哪里找到它? - user3376708
@user3376708,已更新答案以回答您的第一个问题。对于您的第二个问题,是的 - 我认为您只需要在 MyBall 上调用 repaint() 即可。 - matt forsythe
为什么这在不同的布局中不能工作?如果我要制作一个真正的组件,我不是想要使组件能够在每个布局形式中使用吗? - user3376708
@camickr我说“_有时候_这是必要的”,因为它取决于你打算如何使用它。有些布局会强加一个大小限制到你的组件上,并完全忽略大小信息。对于某些组件来说,这可能是有意义的(例如,如果你的组件只是试图绘制一些漂亮的东西来占据空白空间)。切换到BorderLayout可以解决这个问题,因为BorderLayout的默认值是CENTER,这将允许组件显示。 - matt forsythe
Camickr所说的是,你真的应该实现get*Size()方法,以便布局管理器可以完成它们的工作。许多布局管理器使用最大、最小和首选大小来确定如何在容器中分配空间给其中的各个组件。如果你不实现这些方法,那么你的组件将无法与其他组件(甚至是自己)一起使用这些布局。如果你不在这些容器中使用你的组件,这可能会起作用,但这并不是真正的“正确做法”。这就是为什么你的组件不能与GridBagLayout一起使用的原因。 - matt forsythe
显示剩余3条评论

1
我对你的Java类进行了一些微调,唯一的更改是将你的新MyBall直接添加到JFrame的内容面板中,请尝试运行此程序,你会在你的JFrame上看到一个红色圆形。
public class TestBall {
    public static void main(String[] args) {
        new TestBall();
    }

    public TestBall() {

        JFrame frame = new JFrame("Testing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.getContentPane().add(new MyBall(30,30,10));
        frame.pack();
        frame.setSize(500, 300);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

class MyBall extends JComponent
{
    private static final long serialVersionUID = 1L;
    public MyBall() { }
    public MyBall(int x, int y, int diameter)
    {
        super();
        this.setLocation(x, y);
        this.setSize(diameter, diameter);
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.setColor(Color.red);
        g.fillOval(0, 0, 100, 100);
    }
}

0
构造函数:我们只需将位置设置为通过构造函数参数传递的点。这是该组件所在的位置。同样的方式,我们设置大小(width x height)。 paintComponent:在此处,我们只需在传递的图形对象上绘制一些椭圆。
另一部分只是测试,以显示组件已正确创建和显示。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接