Написание пользовательского JPanel, который будет следовать спецификациям LayoutManager

Я пытаюсь кодировать пользовательский 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();

    }
}

Не чувствую себя обязанным отлаживать эту стену кода, просто некоторый контекст, в котором я нахожусь.

2 ответа

Решение
  • Компонент должен предоставить, по крайней мере, предпочитаемый размер для родительского менеджера компоновки, чтобы определить, как лучше его выложить. Вы не должны делать расчеты о своем размере, ожидайте, чтобы соответствовать этим требованиям...
  • При рисовании графический контекст вашего компонента уже начал переводиться в положение 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) {
    }
}

Я настоятельно рекомендую вам взглянуть на Выполнение пользовательской живописи

Я пытаюсь кодировать пользовательский JPanel, который следует за компоновщиком содержащего JPanel

Компоненту не важно, к какой панели он добавлен, поэтому не важно, какой менеджер компоновки использует родительская панель.

Пользовательский компонент переопределяет методы getPreferredSize(), getMinimumSize() и getMaximumSize(), чтобы менеджер макета родительского контейнера мог использовать эти предложения для определения фактического размера компонента.

Тогда в вашем paintComponent() Использование метода Используйте методы getWidth() и geHeight(), чтобы определить фактический размер вашего компонента. Затем вы красите свой компонент соответственно. Ваша логика должна определить, как нарисовать ваш компонент на основе возможного размера.

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

Ваш код рисования должен использовать (0, 0) для местоположения X/Y, так как вы пытаетесь очистить всю область вашей панели. Значения getX()/getY() могут отличаться от нуля, поскольку менеджер макета родительского контейнера будет определять местоположение панели.

Другие вопросы по тегам