какой менеджер компоновки Java подходит для этой задачи? - PullRequest
4 голосов
/ 29 августа 2011

У меня есть родитель JPanel с 3 детьми JPanel внутри. Все они в настоящее время используют GridLayout и вместе представляют класс UML. Проблема в том, что когда я добавляю новый атрибут или метод, все 3 JPanel растут до одинакового размера.

Желание поведения таково:

  1. Размер поля заголовка всегда остается неизменным при добавлении метода или атрибута.
  2. При добавлении метода увеличивается только панель методов, а размер заголовка и панели атрибутов остается неизменным.
  3. При добавлении атрибута увеличивается только панель атрибутов, а размер других панелей остается прежним.

Родительский JPanel уже может автоматически увеличиваться / уменьшаться при добавлении метода / атрибута. Я играю с GridBagLayout atm, но я не приближаюсь к желаемым результатам.

Есть ли простой (или более простой) способ решить эту проблему?!

Вот несколько фотографий, чтобы показать мою ситуацию.

Недавно созданный класс UML => enter image description here так он себя ведет в настоящее время => enter image description here

Но я хочу это => enter image description here или это => enter image description here или это => enter image description here

Edit2: добавлены новые картинки для наглядности. Мне ужасно жаль, если оригинальная версия вводила в заблуждение.

Edit3: ДА! Я разобрал это! Чувствовал как навсегда !! Вот SSEEC:

Детская панель

    import java.awt.Component;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.MouseInputListener;

    public class APanel extends JPanel{
        private JTextField tf;

    public APanel() {
        this.setLayout(new GridLayout(0,1));
        this.addMouseListener(mouseInputListener);
      }

    MouseInputListener mouseInputListener = new MouseInputAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
        System.out.println("Adding a new text field!");
        tf = MyTF.create("Double click");
        addNewTF(tf);
        Component source = (Component) e.getSource();
        Container c = source.getParent();
        while(true) {
            if(c instanceof PPanel)
                break;
            else
                c=c.getParent();
        }
        PPanel p = (PPanel) c;
        p.expand();
        }
    };

    public void addNewTF(JTextField tf) {
        this.add(tf);
        this.setSize(this.getWidth(), this.getHeight()+tf.getHeight());
        this.revalidate();
        this.repaint();

    }
}

Родительская панель:

    import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class PPanel extends JPanel{
    //private APanel panel1;
    private JPanel panel1;
    private APanel panel2;
    private APanel panel3;
    public PPanel() {

        this.setLayout(new BoxLayout(this , BoxLayout.Y_AXIS));
        this.setBackground(Color.black);

        panel1 = new JPanel();
        panel1.setLayout(new GridLayout(0,1));
        panel1.add(new JTextField("title"));
        panel2 = new APanel();
        panel2.setBorder(BorderFactory.createLineBorder(Color.red));
        panel3 = new APanel();
        panel3.setBorder(BorderFactory.createLineBorder(Color.black));

        this.add(panel1);
        this.add(Box.createRigidArea(new Dimension(0,1)));
        this.add(panel2);
        this.add(panel3);


    }
    public void expand() {
        this.setSize(this.getWidth(), this.getHeight()+33);
        this.revalidate();
        this.repaint();
    }
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        PPanel panel = new PPanel();
        panel.setBounds(10, 10, 100, 150);
        JPanel c = new JPanel(null);
        c.add(panel);
        frame.add(c);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(new Dimension(350, 300));
        frame.setTitle("Demo");
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

Класс помощи:

    import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import javax.swing.JTextField;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.MouseInputListener;

public class MyTF {
    public static JTextField create(String name) {
        final JTextField tf = new JTextField(name);
        System.out.println(tf.getPreferredSize());
        tf.setPreferredSize(new Dimension(100,33));
        tf.addMouseListener(mouseInputListener);
        return tf;
    }

    static MouseInputListener mouseInputListener = new MouseInputAdapter() {
        @Override
            public void mouseClicked(MouseEvent e) {
                Component source = (Component) e.getSource();
                Container c = source.getParent();
                while(true) {
                    if(c instanceof PPanel)
                        break;
                    else if(c instanceof APanel)
                    {
                        c.dispatchEvent(e);
                        c = c.getParent();
                        break;

                    }
                    else
                        c=c.getParent();
                }
                c.dispatchEvent(e);
        }

    };
}

Я отказался от игры с GridBagLayout, это было слишком много для меня. Затем я попробовал borderLayout, как было предложено, но не смог заставить его работать так, как я хочу. Затем, наконец, BoxLayout, он должен был сработать, но в моем коде была ошибка! Поэтому, когда я попробовал 0бербозный код предложить и поиграть с ним, он потерпел неудачу! До тех пор, пока я не закончил SSEEC, не выполнил окончательную компиляцию и не запустил ее, прежде чем решил опубликовать (я практически сдался), затем я понял, что это работает не мешать друг другу.

Я был как WTF!

Вернулся к моему коду и сравнил его с SSEEC, и была ошибка, код для увеличения высоты панели был в неправильном месте, так что они как будто перебирали друг друга.

Еще лучше! Я могу указать расстояние между средней рамкой с рамкой над и под ней на один пиксель. Это означает, что я все еще могу использовать трюк от mKorbel, чтобы нарисовать черту, разделяющую эти ящики!

Редактировать 4: есть ли способ установить размер компонента? Если вы запустите SSEEC, вы заметите, что как только JTextField добавлен, он огромен! Это больше, чем контейнер ...

Ответы [ 4 ]

6 голосов
/ 29 августа 2011

Я предлагаю вам использовать BoxLayout.Вот учебник .Играя с клеями и жесткой областью, вы можете получить практически всю желаемую раскладку.В вашем случае код должен выглядеть примерно так:

JPanel container = new JPanel();
container .setLayout(new BoxLayout(container , BoxLayout.Y_AXIS));

JPanel childTop = new JPanel();
JPanel childCenter = new JPanel();
JPanel childBottom = new JPanel();


childTop.setMaximumSize(...);
childBottom.setMaximumSize(...);

container.add(childTop);
container.add(Box.createVerticalGlue());
container.add(childCenter);
container.add(Box.createVerticalGlue());
container.add(childBottom);

Когда вам нужно вставить нового потомка, не забудьте вставить его в правильное положение: между одним из клеев и childCenter.Например:

container.add(newChild, 2) ;
4 голосов
/ 29 августа 2011

возможно, с помощью BorderLayout вы можете сделать это

(пример с базовыми вещами revalidate(); + repaint(); против pack();)

enter image description here enter image description here enter image description here

из кода

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;

public class AddComponentsAtRuntime {

    private JFrame f;
    private JPanel panel;
    private JCheckBox checkValidate, checkReValidate, checkRepaint, checkPack;

    public AddComponentsAtRuntime() {

        JButton b = new JButton();
        b.setBackground(Color.red);
        b.setBorder(new LineBorder(Color.black, 2));
        b.setPreferredSize(new Dimension(600, 10));
        panel = new JPanel(new GridLayout(0, 1));
        panel.add(b);
        JPanel panelnorth = new JPanel();
        panelnorth.setPreferredSize(panel.getPreferredSize());
        f = new JFrame();
        f.setLayout(new BorderLayout(5, 5));
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(panelnorth,BorderLayout.NORTH);
        f.add(panel,BorderLayout.CENTER);
        f.add(getCheckBoxPanel(),BorderLayout.SOUTH);
        f.setLocation(200, 200);
        f.pack();
        f.setVisible(true);
    }

    private JPanel getCheckBoxPanel() {
        checkValidate = new JCheckBox("validate");
        checkValidate.setSelected(false);
        checkReValidate = new JCheckBox("revalidate");
        checkReValidate.setSelected(false);
        checkRepaint = new JCheckBox("repaint");
        checkRepaint.setSelected(false);
        checkPack = new JCheckBox("pack");
        checkPack.setSelected(false);
        JButton addComp = new JButton("Add New One");
        addComp.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JButton b = new JButton();
                b.setBackground(Color.red);
                b.setBorder(new LineBorder(Color.black, 2));
                b.setPreferredSize(new Dimension(600, 10));
                panel.add(b);
                makeChange();
                System.out.println(" Components Count after Adds :" + panel.getComponentCount());
            }
        });
        JButton removeComp = new JButton("Remove One");
        removeComp.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                int count = panel.getComponentCount();
                if (count > 0) {
                    panel.remove(0);
                }
                makeChange();
                System.out.println(" Components Count after Removes :" + panel.getComponentCount());
            }
        });
        JPanel panel2 = new JPanel();
        panel2.add(checkValidate);
        panel2.add(checkReValidate);
        panel2.add(checkRepaint);
        panel2.add(checkPack);
        panel2.add(addComp);
        panel2.add(removeComp);
        return panel2;
    }

    private void makeChange() {
        if (checkValidate.isSelected()) {
            panel.validate();
        }
        if (checkReValidate.isSelected()) {
            panel.revalidate();
        }
        if (checkRepaint.isSelected()) {
            panel.repaint();
        }
        if (checkPack.isSelected()) {
            f.pack();
        }
    }

    public static void main(String[] args) {
        AddComponentsAtRuntime makingChanges = new AddComponentsAtRuntime();
    }
}
3 голосов
/ 29 августа 2011

К сожалению, я не уверен на 100%, что понял ваш макет.Будет лучше, если вы сможете прикрепить картинку.

Но если Grid Layout растет не так, как вы хотите, вы можете использовать GridBagLayout, который может делать почти все, но немного сложнее, или использовать комбинацию Border и других макетов.

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

Установите флажок BoxLayout.

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

Поскольку вы обновили свой вопрос сейчас, я могу с уверенностью сказать, что вы можете определить BorderLayout с Севером, Югом и Центром.

Центр будет содержать сетку с 2 рядами.Каждый ряд снова будет содержать макет границы.Верхняя граница макета будет содержать другую панель на юге.Расположение нижней границы будет содержать расположение границ на севере.

Каждый из этих макетов будет содержать еще один макет границы с меткой на западе и текстовым полем в центре.

1 голос
/ 29 августа 2011

Вы можете использовать GridBagLayout для этого. Я думаю, что у меня получилось

  • добавить четвертую субпанель на верхнюю панель
  • установите для весомых трех верхних панелей значение 0
  • установите весовой коэффициент для нижней (новой) панели на 1
  • В зависимости от того, какую технику вы используете для визуализации текста на вложенных панелях, вам может потребоваться явно указать предпочтительный размер вложенных панелей.
  • когда вы добавляете новые элементы в подпанели, вам нужно будет сделать недействительным и изменить макет всего.
...