Java, which layout manager is suitable for this task?

I have a JPanel parent with three JPanel children inside. All of them currently use GridLayout and together represent a UML class. The problem is that when I add a new attribute or method, all 3 JPanels grow the same size.

Desire is that:

  • The size of the header field always remains the same when adding a method or attribute.
  • When adding a method, only the method panel increases, and the size of the title bar and attribute remains unchanged.
  • When adding an attribute, only the attribute panel grows, while the size of the remaining panels remains unchanged.

Parent JPanel can already automatically grow / contract whenever a method / attribute is added. I play with the GridBagLayout atm, but I do not get anywhere near the results of desire.

Is there a simple (or simpler) way to solve this problem ?!

Here are some photos to show my situation.

Newly created UML class => enter image description here this is how he is currently behaving => enter image description here

But I want this => enter image description here or this => enter image description here or this => enter image description here

Edit2: added new photos for clarity. I'm sorry if the original version is misleading.

Edit3: YESS! I took it apart! Feeling forever !! Here is the SSEEC:

Kids panel

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

Parent Panel:

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

Help Class:

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

I refused to play with GridBagLayout, it was too much for me. Then I tried borderLayout, as suggested, but could not get it to work, just like me. Then, finally, BoxLayout, it should have worked, but there was an error in my code! So when I tried the 0verbose code, offering and playing with it, it failed! Until I finished SSEEC, did the final compilation and started it before I decided to publish (I practically gave up at this point), then I realized that it worked ... A panel that can grow in its own space, they do not interfere with each other.

I was like WTF!

I returned to my code and compared it with SSEEC, and an error occurred, the code to increase the height of the panel was in the wrong place, so they kind of ate each other.

Even better! I can specify the distance between the middle box with the field above and below it by one pixel. This means that I can still use the mKorbel trick to draw a return line separating these fields!

Edit 4: is there a way to set the size of the component? If you run SSEEC, you will notice that after adding a JTextField it will be huge! It is more than a container ...

+4
source share
4 answers

I suggest you use BoxLayout. Here's a tutorial . Playing with adhesives and a tough area, you can get almost all the necessary layouts. In your case, the code should be something like this:

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

If you need to insert a new child, do not forget to insert it in the desired position: between one glue and the child center. For instance:

 container.add(newChild, 2) ; 
+6
source

maybe this is with BorderLayout you can do it

(basic material revalidate(); + repaint(); compared to pack(); )

enter image description hereenter image description hereenter image description here

from code

 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(); } } 
+4
source

Unfortunately, I'm not 100% sure that I understood your layout. It will be better if you can attach the image.

But if the Grid Layout does not grow the way you want, you can use GridBagLayout, which can do almost everything, but a little more complicated, or use a combination of Border and other layouts.

Perhaps several border layouts can help. In this layout, the center grows rapidly, and the north, south, west and east grow more slowly. Try to use them.

Also check the Layout box.

If you are going to create many complex dialog boxes, MigLayout . Although there is a certain learning curve, this layout will really help you save hours and days.

Since you updated your question now, I can definitely say that you can define BorderLayout, with north, south, and center.

The center will contain a two-row grid layout. Each line will again contain borders. The upper border will contain another panel in the south. The lower border will contain the border border in the north.

Each of these layouts will contain another border with a label in the west and a text box in the center.

+3
source

You can use GridBagLayout for this. I think it worked for me

  • add the fourth subpanel to the top panel.
  • set the top three panels to 0
  • set the weight for the bottom (new) panel to 1
  • depending on what method you use to render the text in the subpanels, you may need to explicitly specify the preferred size of the sub-panels.
  • when you add new elements in the subpanels, you will need to cancel and redo all of this.
+1
source

Source: https://habr.com/ru/post/1369407/


All Articles