问题
I built a class that extends JPanel
, and I have been setting a size on it every time. But now I need multiple instances of that JPanel
sub-class to exist on another panel. I am using GridBagLayout
, but my components disappear when I resize the Frame
or take away the setSize(800,100)
from the JPanel
subclass. How do I built components that will obey these layout managers
?
I want my custom component to be able to fit to the size that the layout manager asks for.
Here is my custom component
public class GridPanel extends JPanel implements MouseMotionListener, MouseListener{
private Rectangle offdutyRect, sbRect, driveRect, onRect;
private int delta = 60;
private int[][] gridArray;
int draggedStartX = -1;
int draggedStartY = -1;
private int dutyStatusSpacing = 60;
private int totalSpacing = 80;
public GridPanel(){
super();
this.setSize(new Dimension(800, 100));//without this it doesn't display
this.addMouseMotionListener((MouseMotionListener) this);
this.addMouseListener(this);
int gridArrayColumns = 24*60/delta;
gridArray = new int[4][gridArrayColumns];
int r = 0;
int rHeight = this.getHeight()/4;
offdutyRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, this.getWidth() - totalSpacing, rHeight);
r++;
sbRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, this.getWidth() - totalSpacing, rHeight);
r++;
driveRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, this.getWidth() - totalSpacing, rHeight);
r++;
onRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, this.getWidth() - totalSpacing, rHeight);
Rectangle rect = null;
for(r = 0; r < gridArray.length; r++){
if(r == 0){
rect = offdutyRect;
}else if(r == 1){
rect = sbRect;
}else if(r == 2){
rect = driveRect;
}else if(r == 3){
rect = onRect;
}
//I haven't actually derived any of these things, just my best guesses.
int len = gridArray[r].length;
int width = (int) (rect.getWidth()/len);
rect.setSize((int)(width*len), (int) rect.getHeight());
}
}
public void paintComponent(Graphics g){
g.clearRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
//the center black bar for duty status "placeholders"
g.setColor(Color.black);
g.drawRect(getX(), getY(), getWidth() - 1, getHeight() - 1);
g.drawRect((int)offdutyRect.getX(), (int)offdutyRect.getY() + (int)offdutyRect.getHeight()/2, (int)offdutyRect.getWidth(), 1);
g.drawRect((int)sbRect.getX(), (int)sbRect.getY() + (int)sbRect.getHeight()/2, (int)sbRect.getWidth(), 1);
g.drawRect((int)driveRect.getX(), (int)driveRect.getY() + (int)driveRect.getHeight()/2, (int)driveRect.getWidth(), 1);
g.drawRect((int)onRect.getX(), (int)onRect.getY() + (int)onRect.getHeight()/2, (int)onRect.getWidth(), 1);
g.setColor(Color.pink);
g.drawRect((int)offdutyRect.getX(), (int)offdutyRect.getY(), (int)offdutyRect.getWidth(), (int)offdutyRect.getHeight());
g.drawRect((int)sbRect.getX(), (int)sbRect.getY(), (int)sbRect.getWidth(), (int)sbRect.getHeight());
g.drawRect((int)driveRect.getX(), (int)driveRect.getY(), (int)driveRect.getWidth(), (int)driveRect.getHeight());
g.drawRect((int)onRect.getX(), (int)onRect.getY(), (int)onRect.getWidth(), (int)onRect.getHeight());
//draw the array
g.setColor(Color.green);
Rectangle rect = null;
for(int r = 0; r < gridArray.length; r++){
if(r == 0){
rect = offdutyRect;
}else if(r == 1){
rect = sbRect;
}else if(r == 2){
rect = driveRect;
}else if(r == 3){
rect = onRect;
}
//I haven't actually derived any of these things, just my best guesses.
int len = gridArray[r].length;
int width = (int) (rect.getWidth()/len);
int height = (int) rect.getHeight() - 2;
for(int c = 0; c < gridArray[r].length; c++){
if(gridArray[r][c] == 1){
int x = (int) (rect.getX() + width*c);
int y = (int) rect.getY() + 2;
g.fillRect(x, y, width, height);
}
}
}
}
And here is how I am adding them to the container using gridbag
public void actionPerformed(ActionEvent e) {
System.out.println("action performed" + panels.size());
removeAll();
repaint();
panels.add(new GridPanel());
int r = 0;
GridBagConstraints c = new GridBagConstraints();
for(int i = 0; i < panels.size(); i++){
JLabel label = new JLabel("day " + i);
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = r;
this.add(label, c);
r++;
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = r;
c.fill = GridBagConstraints.HORIZONTAL;
this.add(panels.get(i), c);
r++;
}
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = r;
c.fill = GridBagConstraints.HORIZONTAL;
BufferedImage img = null;
try {
img = ImageIO.read(this.getClass().getResource("/res/add.png"));
} catch (IOException ex) { }
JButton addButton = new JButton();
addButton.setIcon(new ImageIcon(img));
addButton.addActionListener(this);
this.add(addButton, c);
}
When I do this "action performed" that is supposed to add it, my custom component shows up in the top left corner, but I have to resize the window to get all the components to show.
回答1:
Many layout managers make use of the values returned by getPreferredSize
, getMinimumSize
and getMaximumSize
.
GridBagLayout
is one of those which will, generally, where possible, try and honor all three.
In your custom component, override (at least), the getPreferredSize
method and return, to the best of you knowledge, the size of the component you need.
If the component is using a layout manager with other components in it, you should always let the layout manager make this determination (which is the default behavior)
Updated
Don't forget, when adding or removing components, you may be required to call revalidate
to force the container hierarchy to update it's layout(s)
来源:https://stackoverflow.com/questions/17460217/writing-a-jpanel-subclass-that-will-obey-gridbaglayout