java哪个布局管理器适合这个任务?

时间:2011-08-28 21:27:36

标签: java swing layout-manager

我有一个JPanel父级,里面有3个JPanel子级。他们目前都使用GridLayout并一起代表一个UML类。问题是,当我添加新属性或方法时,所有3个JPanel都会增长到相同的大小。

欲望行为是:

  1. 每当添加方法或属性时,标题框的大小始终保持不变。
  2. 添加方法时,只有方法面板增长,标题和属性面板的大小保持不变。
  3. 添加属性时,只有属性面板增长,其他面板大小保持不变。
  4. 无论何时添加方法/属性,父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:YESS!我已经整理好了!感觉就像永远!这是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的efford,这对我来说太过分了。然后我按照建议尝试了borderLayout,但是无法让它像我想要的那样工作。然后最后BoxLayout,它应该工作但我的代码中有一个错误!因此,当我尝试使用0verbose代码建议并使用它时,它失败了!直到我完成了SSEEC,最后编译并在我决定发布之前运行它(我此时几乎放弃了)然后我意识到它有效......可以在他们自己的空间中成长的面板,他们不要互相干扰。

    我就像WTF!

    回到我的代码并将其与SSEEC进行比较并且存在一个错误,扩展面板高度的代码位于错误的位置,因此它们有点像进入彼此的空间。

    更好!我可以指定中间框与其上方和下方的框之间的距离为一个像素。这意味着我仍然可以使用mKorbel的技巧来绘制背线来分隔这些盒子!

    编辑4:有没有办法让我设置一个组件的大小?如果您运行SSEEC,您会注意到一旦添加了JTextField,它就是巨大的!它比容器大......

4 个答案:

答案 0 :(得分:6)

我建议你使用BoxLayout。这是一个tutorial。使用胶水和刚性区域,您可以获得几乎所有所需的布局。在你的情况下,代码应该是这样的:

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) ;

答案 1 :(得分:4)

也许通过使用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();
    }
}

答案 2 :(得分:3)

不幸的是,我不是100%确定我理解你的布局。如果你能附上图片会更好。

但是如果网格布局增长不是你想要的,你可以使用GridBagLayout,它可以做几乎所有事情,但有点复杂或使用边框和其他布局的组合。

可能有几种边框布局可以帮到你。在这个布局中心正在快速增长,而北部,南部,西部和东部正在增长较慢。尝试使用它们。

也检查BoxLayout。

如果您要创建许多复杂的对话框,请查看MigLayout。虽然存在一些学习曲线,但这种布局确实可以帮助您节省时间和天数。

由于您现在更新了问题,我可以肯定地说您可以使用North,South和Center定义BorderLayout。

中心将包含2行的网格布局。每行将再次包含Border layeout。上边框布局将包含南部的其他面板。较低的边框布局将包含北方的边框布局。

每个布局都将包含另一个边框布局,其中西边是标签,中间是文本字段。

答案 3 :(得分:1)

您可以使用GridBagLayout。我认为对我有用的是

  • 将第四个子面板添加到顶部面板
  • 将前三个面板的重量设置为0
  • 将底部(新)面板的重量设置为1
  • 根据您在子面板中呈现文本所使用的技术,您可能需要明确设置子面板的首选大小。
  • 当您向子面板添加新项目时,您需要使整个项目无效并重新布局。