编写一个服从GridBagLayout的JPanel子类?

时间:2013-07-04 00:35:38

标签: java swing jpanel layout-manager preferredsize

我构建了一个扩展JPanel的类,我每次都在设置一个大小。但是现在我需要在另一个面板上存在该JPanel子类的多个实例。我正在使用GridBagLayout,但当我调整Frame的大小或从setSize(800,100)子类中删除JPanel时,我的组件会消失。如何构建符合这些layout managers的组件?

我希望我的自定义组件能够适应布局管理器要求的大小。

这是我的自定义组件

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);
        }
        }
    }
    }

以下是我如何使用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);


    }

当我执行“应该执行的操作”应该添加它时,我的自定义组件显示在左上角,但我必须调整窗口大小以显示所有组件。

1 个答案:

答案 0 :(得分:4)

许多布局管理员都会使用getPreferredSizegetMinimumSizegetMaximumSize返回的值。

GridBagLayout是其中之一,通常会在可能的情况下尝试并尊重这三者。

在自定义组件中,覆盖(至少)getPreferredSize方法,并根据您的知识返回所需组件的大小。

如果组件使用的布局管理器中包含其他组件,则应始终让布局管理器进行此确定(这是默认行为)

<强>更新

不要忘记,在添加或删除组件时,可能需要调用revalidate来强制容器层次结构更新它的布局