0

我正在尝试编写一个自定义 JPanel,它遵循包含 JPanel 的布局管理器(我正在使用 gridbag)。我的自定义 JPanel 有点太长了,无法粘贴到这里,但是要覆盖所有方法的清单以使其正常工作。

这是我的自定义 JPanel 的摘录:

        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 = 100;

            public GridPanel(){
            this.setSize(new Dimension(800, 100));
            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);
            }
            }
        }
        }
    //implement setSize
    public void setSize(Dimension d){

    if(gridArray == null){

        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, (int)d.getWidth() - totalSpacing, rHeight);
    r++;
    sbRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, (int)d.getWidth() - totalSpacing, rHeight);
    r++;
    driveRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, (int)d.getWidth() - totalSpacing, rHeight);
    r++;
    onRect = new Rectangle(this.getX() + dutyStatusSpacing, this.getY() + r*rHeight, (int)d.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 class GridContainer extends JPanel implements ActionListener{
    List<GridPanel> panels = new ArrayList<GridPanel>();

    public GridContainer(){
    GridBagLayout gb = new GridBagLayout();
    this.setLayout(gb);
    GridBagConstraints c = new GridBagConstraints();

    c.gridx = 0;
    c.gridy = 0;
    c.weightx = .5;
    c.weighty = .5;
    c.fill = GridBagConstraints.HORIZONTAL;
    BufferedImage img = null;
    try {
        img = ImageIO.read(this.getClass().getResource("/res/add.png"));
    } catch (IOException e) { }
    JButton addButton = new JButton();
    addButton.setIcon(new ImageIcon(img));
    addButton.addActionListener(this);
    this.add(addButton, c);
    }

    public void actionPerformed(ActionEvent e) {
    System.out.println("action performed"  +  panels.size());
    this.setLayout(new GridBagLayout());
    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;
            c.weightx = 1;
            c.weighty = 1;
            this.add(label, c);
            r++;

            c = new GridBagConstraints();
            c.gridx = 0;
            c.gridy = r;
            c.weightx = 1;
            c.weighty = 1;
            c.fill = GridBagConstraints.HORIZONTAL;
            this.add(panels.get(i), c);
            r++;
    }

    c = new GridBagConstraints();
    c.gridx = 0;
    c.gridy = r;
    c.weightx = 1;
    c.weighty = 1;
    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);
    repaint();

    }
}

不要觉得有义务调试这堵代码墙,只是我所在位置的一些上下文。

4

2 回答 2

5

我正在尝试编写一个遵循包含 JPanel 的布局管理器的自定义 JPanel

组件不关心它被添加到哪个面板,因此它也不关心父面板使用什么布局管理器。

自定义组件会覆盖 getPreferredSize()、getMinimumSize() 和 getMaximumSize() 方法,以便父容器的布局管理器可以使用这些建议来确定组件的实际大小。

然后在您的paintComponent()方法中使用 getWidth() 和 geHeight() 方法来确定组件的实际大小。然后你相​​应地绘制你的组件。您的逻辑需要根据最终大小确定如何绘制组件。

g.clearRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());

您的绘画代码应该使用 (0, 0) 作为 X/Y 位置,因为您试图清除面板的整个区域。getX()/getY() 值可能不为零,因为父容器的布局管理器将确定面板的位置。

于 2013-07-04T02:32:09.920 回答
3
  • 一个组件至少应该为父布局管理器提供一个 preferredSize,以确定它应该如何最好地布局。你不应该计算你的尺寸期望满足这些要求......
  • 绘制时,组件的图形上下文已经开始转换为组件的 x/y 位置。这意味着您的组件的左上角实际上是 0x0
  • 你应该打电话super.paintComponent。这非常重要,因为它为绘制准备图形上下文,这在处理透明组件时更加重要

在此处输入图像描述

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 = 100;

    public GridPanel() {
        setBackground(Color.WHITE);
        //this.setSize(new Dimension(800, 100));
        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(dutyStatusSpacing, r * rHeight, this.getWidth() - totalSpacing, rHeight);
        r++;
        sbRect = new Rectangle(dutyStatusSpacing, r * rHeight, this.getWidth() - totalSpacing, rHeight);
        r++;
        driveRect = new Rectangle(dutyStatusSpacing, r * rHeight, this.getWidth() - totalSpacing, rHeight);
        r++;
        onRect = new Rectangle(dutyStatusSpacing, 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) {
        super.paintComponent(g);
        //the center black bar for duty status "placeholders"
        g.setColor(Color.black);
        g.drawRect(0, 0, 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);
                }
            }
        }
    }

    //implement setSize
    //        public void setSize(Dimension d) {
    @Override
    public void doLayout() {

        if (gridArray == null) {

            int gridArrayColumns = 24 * 60 / delta;
            gridArray = new int[4][gridArrayColumns];
        }
        int r = 0;
        int rHeight = this.getHeight() / 4;
        offdutyRect = new Rectangle(dutyStatusSpacing, r * rHeight, (int) getWidth() - totalSpacing, rHeight);
        r++;
        sbRect = new Rectangle(dutyStatusSpacing, r * rHeight, (int) getWidth() - totalSpacing, rHeight);
        r++;
        driveRect = new Rectangle(dutyStatusSpacing, r * rHeight, (int) getWidth() - totalSpacing, rHeight);
        r++;
        onRect = new Rectangle(dutyStatusSpacing, r * rHeight, (int) 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());
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

    @Override
    public void mouseDragged(MouseEvent e) {
    }

    @Override
    public void mouseMoved(MouseEvent e) {
    }

    @Override
    public void mouseClicked(MouseEvent e) {
    }

    @Override
    public void mousePressed(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }
}

我强烈建议您看看Performing Custom Painting

于 2013-07-04T03:01:22.933 回答