Question

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.

Was it helpful?

Solution

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)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top