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

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

    }
}

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


person ceptno    schedule 04.07.2013    source источник
comment
Вместо setSize вы можете 1- использовать менеджер компоновки; 2- Переопределить doLayout...вы также не звоните super.setSize   -  person MadProgrammer    schedule 04.07.2013
comment
Использовать менеджер компоновки в пользовательской панели JPanel?   -  person ceptno    schedule 04.07.2013
comment
Проблема, с которой я столкнулся с вашим кодом, заключается в том, что панель сетки не имеет предпочтительного размера.   -  person MadProgrammer    schedule 04.07.2013
comment
возможный дубликат Написание подкласса JPanel, который будет подчиняться GridBagLayout?   -  person htz    schedule 04.07.2013
comment
дубликат stackoverflow. com/questions/17460217/   -  person htz    schedule 04.07.2013


Ответы (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) {
    }
}

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

person MadProgrammer    schedule 04.07.2013
comment
Это не отображается сразу после нажатия кнопки добавления, а только после изменения размера окна. С чем это связано и как это исправить? - person ceptno; 04.07.2013
comment
В вашем методе actionPerformed вызовите revalidate в конце метода, чтобы менеджеры компоновки повторно разместили там компоненты. - person MadProgrammer; 04.07.2013

Я пытаюсь закодировать пользовательскую JPanel, которая следует за layoutmanager содержащей JPanel.

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

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

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

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

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

person camickr    schedule 04.07.2013
comment
(супер.paintComponent();)) - person MadProgrammer; 04.07.2013