I have a class Cell
that extends JComponent
. The goal is for a grid of cells to be displayed, and each one be able to handle their own click events, etc. It is basically a flat button.
When I add several cells to a JPanel
only one of them is displayed. If, using the same code, I replace my Cells with Buttons, everything works as expected.
What am I开发者_如何学运维 missing?
Main Method
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);
}
Cell Class
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();
}
}
}
You are adding 3 components, but only one is painted black. Add a red line border to your Cells to see:
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
}
Edit: This line looks sketchy to me:
g.fillRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
Why are you using getX and getY here? These methods return a position information relative to the container not the cell, but then you are using it to draw in a location relative to the cell not the container, so the black rectangle will be drawn off of the visible cell, and this probably isn't what you want. Perhaps you need to use 0 for both instead:
g.fillRect(0, 0, this.getWidth(), this.getHeight());
One obvious bug in this code is the fact that you apply changes to the Graphics object, via setColor(), but you don't roll them back.
This is clearly stated in the Javadocs:
If you override this in a subclass you should not make permanent changes to the passed in Graphics.
The general solution is to spawn a new Graphics object off of the you get as parameter via Graphics.create()
, wrapping your code inside a try-finally
block, and disposing the new Graphics object via Graphics.dispose()
in the finally clause.
精彩评论