JComponent.setСвязывает последний JComponent в неправильном месте

В последнее время у меня были некоторые проблемы со Swing. Я пытаюсь на лету сделать что-то вроде изображения ниже, чтобы проиллюстрировать структуры данных для алгоритмов.

 изображение записной книжки
(источник: ius.edu)

Все, что я пытался сделать в следующем классе, это нарисовать несколько прямоугольников с числами на них. и переведите их, однако последний прямоугольник рисуется в 0,0. Я в тупике.

Если вы добавите JPanel (закомментировано) после цикла, он отрисуется, как и ожидалось.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class DrawingRect {

    public static void main(String[] args) {
        DrawingRect d = new DrawingRect();
    }

    public DrawingRect() {

        JFrame frame = new JFrame("Drawing a rect");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel swingPanel = new JPanel();
        swingPanel.setPreferredSize(new Dimension(500, 500));

        swingPanel.setVisible(true);

        swingPanel.setLayout(new BorderLayout(0, 0));

        int base = 15;
        for (int i = 1; i <= 25; i++) {
            Graphic re = new Graphic(i);

            //translating the graphic
            re.setBounds(base + 30 * i, base + 20 * i, 110, 110);


            swingPanel.add(re);
        }


        // if say I add a JPanel in here as the last element
        // then the boxes will draw correctly.
        //swingPanel.add(new JPanel());

        swingPanel.setPreferredSize(new Dimension(800, 600));

        frame.getContentPane().add(swingPanel);

        frame.pack();
        frame.setVisible(true);
    }

    public class Graphic extends JComponent {

        private static final long serialVersionUID = 1L;
        private static final int PREF_W = 100;
        private static final int PREF_H = 100;
        int id;

        public Graphic(int id) {
            this.id = id;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2 = (Graphics2D) g;
            g2.setColor(Color.black);

            g2.setColor(Color.black);
            g2.drawRoundRect(0, 0, 30, 30, 20, 20);

            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

            Font font = new Font("", Font.PLAIN, 13);
            g2.setFont(font);

            g2.drawString("" + id, 15, 20);
        }

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

person Andrew    schedule 13.04.2012    source источник


Ответы (2)


По умолчанию макет для JPanel равен FlowLayout, но вы позиционирование компонентов, как если бы макет был null. Более того, вы рисуете контент, который вложенный компонент может делать автоматически.

Вместо этого добавьте несколько JPanel, содержащих JLabel, в содержащую панель, содержащую GridLayout. При необходимости используйте пустые панели. Переопределите paintComponent() на внешней панели для рисования соединительных линий.

Приложение: каждый раз, когда возникает соблазн использовать абсолютное позиционирование, альтернативой может быть JInternalFrame. Похожие примеры можно найти здесь и здесь.

Приложение: Если проект выходит за рамки стадии прототипа, также рассмотрите возможность Менеджер пользовательских макетов.

person trashgod    schedule 13.04.2012
comment
Спасибо, установка для макета значения null дает мне результат, который мне нужен, однако я все еще использую JPanel. - person Andrew; 14.04.2012

Это потому, что вы используете BorderLayout. Вы можете проверить это, изменив строку добавления, включив в нее конкретное расположение макета: swingPanel.add(re,BorderLayout.SOUTH).

Что касается решения, почему бы не нарисовать все прямоугольники на картинке и обновить их в конце цикла? Или добавление в JPanel является частью вашей демонстрации?

person Youssef G.    schedule 13.04.2012
comment
frame имеет BorderLayout по умолчанию, но swingPanel et infra имеют FlowLayout по умолчанию. +1 за предложение закадровой композиции. - person trashgod; 14.04.2012
comment
@trashgod, не могли бы вы объяснить, почему фрейм с Borderlayout, а панель с FlowLayout? Я не вижу макета, установленного на фрейме, поэтому я предполагаю, что он имеет макет по умолчанию, но для swingPanel явно установлено значение BorderLayout. Изменение или удаление swingPanel.setLayout(new BorderLayout()); показывает ожидаемую схему потока, где все находится в строке и переносится на новую строку, когда больше нет свободного места. - person Youssef G.; 14.04.2012
comment
Ой, моя ошибка; ваш анализ правильный. Я сосредоточился на конструкторе без аргументов new JPanel() и пропустил последующий setLayout(). Спасибо за уточнение. - person trashgod; 14.04.2012