JComponent 不能绘制到 JPanel

7

我有一个自定义组件,继承自JComponent,覆盖了方法paintComponent(Graphics g),但是当我尝试将其添加到JPanel中时,它就无法工作,没有任何东西被绘制。以下是我的代码:

public class SimpleComponent extends JComponent{

int x, y, width, height;

public SimpleComponent(int x, int y, int width, int height){
    this.x = x;
    this.y = y;
}

@Override
public void paintComponent(Graphics g){
    Graphics2D g2 = (Graphics2D) g;
    g2.setColor(Color.BLACK);
    g2.fillRect(x, y, width, height);
}
}


public class TestFrame{
public static void main(String[] args){
    JFrame frame = new JFrame();
    JPanel panel = new JPanel();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    panel.setPreferredSize(new Dimension(400, 400));
    frame.add(panel);
    frame.pack();
    frame.setResizable(false);

    SimpleComponent comp = new SimpleComponent(10, 10, 100, 100);
    panel.add(comp);
    frame.setVisible(true);
}
}
2个回答

4

它可以正常工作 - 组件已添加到JPanel中,但它有多大?如果您在GUI渲染后检查此内容,您可能会发现组件的大小为0, 0。

SimpleComponent comp = new SimpleComponent(10, 10, 100, 100);
panel.add(comp);
frame.setVisible(true);

System.out.println(comp.getSize());

考虑让您的JComponent重写getPreferredSize并返回一个有意义的尺寸:

public Dimension getPreferredSize() {
  return new Dimension(width, height);
}

如果您想使用x和y,您可能需要重写getLocation()方法。

编辑
您还需要设置宽度和高度字段!

public SimpleComponent(int x, int y, int width, int height) {
  this.x = x;
  this.y = y;
  this.width = width; // *** added
  this.height = height; // *** added
}

这真的很奇怪,我在 Windows 和 Mac 上都复制了这个问题,结果始终完全相同。 - lilroo
啊,宽度和高度被设置为零。 - lilroo
在记得设置宽度和高度字段后,它仍然无法正常工作,但当我重写了getPreferredSize()方法后,它就可以正常工作了。 - lilroo
@lilroo:是的,你需要两个都做。 - Hovercraft Full Of Eels
1
另外,请调用 super.paintComponent - MadProgrammer
看看我的回答,你就会知道这绝对是错误的答案! - mike rodent

-2

哇!绝对不是正确的答案!

你犯下的第一个绝对的罪过是在非EDT线程中执行所有这些操作!这里没有空间解释...网络上只有大约300亿个地方可以学习。

一旦所有这些代码在EDT(事件分派线程)中以Runnable形式执行,那么:

不需要覆盖preferredSize(尽管如果您愿意,可以这样做)...但是您确实需要设置它。

绝对不应该直接设置大小(heightwidthsetSize())!

您需要做的是让java.awt.Container(例如您的示例中的panel)自行“布局”...有一个方法Container.doLayout(),但正如API文档中所述:

使此容器布置其组件。大多数程序不应直接调用此方法,而应调用validate方法。

因此,解决方案是:

SimpleComponent comp = new SimpleComponent(10, 10, 100, 100);
comp.setPreferredSize( new Dimension( 90, 90 ) );
panel.add(comp);

// the key to unlocking the mystery
panel.validate();

frame.setVisible(true);

顺便说一下,请从我的经验中获益:我花了数小时来理解所有这些validate,invalidate,paintComponent,paint等等的东西...但我仍然觉得自己只是浅尝辄止。


请参见https://dev59.com/62gv5IYBdhLWcg3wD8uY?rq=1 - Hovercraft Full Of Eels
好的,谢谢...但是如果你是那个在这里downvote我的答案的人,那对于未来访问者来说并不是非常有帮助的:我的答案比被接受的答案好得多,而关于setPreferredSize/getPreferredSize的细微差别并没有改变这一点。 - mike rodent
哦...我看到你是已接受答案的回答者!但以您 214k 的声望,您一定知道我所列举的每个要点都是正确的,并且您的答案确实...嗯,我该怎么说呢?留下了改进的空间! - mike rodent

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