Java JPanel将正确显示按钮,但赢得';无法正确显示自定义组件

Java JPanel将正确显示按钮,但赢得';无法正确显示自定义组件,java,swing,Java,Swing,我有一个类Cell,它扩展了JComponent。目标是要显示一个单元格网格,每个单元格都能够处理自己的单击事件等。它基本上是一个平面按钮 当我将几个单元格添加到JPanel时,只显示其中一个单元格。如果使用相同的代码,我将单元格替换为按钮,那么一切都会正常工作 我错过了什么 主要方法 public static void main(String[] args){ JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame

我有一个类
Cell
,它扩展了
JComponent
。目标是要显示一个单元格网格,每个单元格都能够处理自己的单击事件等。它基本上是一个平面按钮

当我将几个单元格添加到
JPanel
时,只显示其中一个单元格。如果使用相同的代码,我将单元格替换为按钮,那么一切都会正常工作

我错过了什么

主要方法

public static void main(String[] args){
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setSize(new Dimension(300,300));
    JPanel jp = new JPanel();
    jp.setLayout(new GridLayout(1, 3));
    if(true){//Use buttons instead of cells
        jp.add(new JButton("Button 1"));
        jp.add(new JButton("Button 2"));
        jp.add(new JButton("Button 3"));
    }
    else{ //Use cells instead of buttons
        Cell a = new Cell(10,0,0);
        Cell b = new Cell(10,0,1);
        Cell c = new Cell(10,0,2);
        jp.add(a,0);
        jp.add(b,1);
        jp.add(c,2);
    }

    f.add(jp);
    f.setVisible(true);
    }
单元类

public class Cell extends JComponent{
    private static int numCells=0;
    private Dimension size;
    private int dt;
    private int dl;
    private Color color;
    public Cell(int size, int dt, int dl){
        numCells++;
        Random rand = new Random();
        this.size = new Dimension(size,size);
        this.dt = dt;
        this.dl = dl;
        this.color = new Color(//Random color, but only in one :r, g, or b
            (numCells%3==0)?rand.nextInt(255):0,
            (numCells%3==1)?rand.nextInt(255):0,
            (numCells%3==2)?rand.nextInt(255):0
    );
        this.setPreferredSize(this.size);
        this.setMaximumSize(this.size);
        this.setMinimumSize(this.size);
        this.setBackground(color);
        this.setVisible(true);
        this.setOpaque(true);
    }
    public void amClicked(){
        JOptionPane.showMessageDialog(this.getParent(), 
                this.toString());
    }

    public String toString(){
        return ""+dt+","+dl;
    }
    public void paintComponent(Graphics g){
                Graphics ng = g.create();
    try{
        super.paintComponent(ng);
        ng.setColor(color); 
        System.out.println(String.format("%d,%d,%d,%d(%d,%d,%d)",
                this.getX(), this.getY(), this.getWidth(), this.getHeight(),
                this.color.getRed(),this.color.getGreen(),this.color.getBlue()));
        ng.fillRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
    }
    finally{
        ng.dispose();
    }
    }


}

这段代码中一个明显的错误是,您通过setColor()将更改应用于图形对象,但没有回滚这些更改

这在以下文件中明确说明:

如果在子类中重写此项,则不应对传入的图形进行永久性更改


一般的解决方案是通过
Graphics.create()
,将代码包装在
try finally
块中,并通过finally子句中的
Graphics.dispose()
处理新的图形对象,从而从您的get as参数中生成一个新的图形对象。

您正在添加3个组件,但只有一个被漆成黑色。在单元格中添加红线边框以查看:

  public Cell(int size, int dt, int dl) {
     numCells++;
     //.... code deleted

     // !!this.color = new Color(Color.BLACK); // *** won't compile!
     color = Color.black;

     //.... code deleted

     this.setOpaque(true);
     setBorder(BorderFactory.createLineBorder(Color.red, 2));  // **** add this
  }
编辑:我觉得这条线很粗略:

     g.fillRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
为什么在这里使用getX和getY?这些方法返回一个相对于容器而不是单元格的位置信息,但是您使用它来绘制相对于单元格而不是容器的位置,因此黑色矩形将从可见单元格中绘制出来,而这可能不是您想要的。也许您需要同时使用0:

     g.fillRect(0, 0, this.getWidth(), this.getHeight());

我原本有随机的颜色,但希望颜色要么是红色,要么是绿色,要么是蓝色。为了避免混淆,我在发布之前删除了这段代码。我把它放回原处,因为“避免混淆”部分不起作用。我明白了代码不起作用的原因:这是您对getX()和getY()的使用。请看上面我的答案。