Suitable LayoutManager for resizable components

sometime ago I read this article, which shows how to implement user-modifiable components in Swing.

The author uses an empty LayoutManager to ensure absolute component positioning. I know that a null layout should never be used, so my question is:

Is there an already implemented LayoutManager that allows absolute positioning of a component, or should I implement it myself?

+6
source share
4 answers

The layout manager really does 3 things:

  • Set the location of the component. Since you need the ability to drag a component around, you do not want your layout manager to do this.

  • Set the size of the component. Since you need to resize the component, you will not want to do this. However, you might want to give the component a default size based on the preferred size of the components. Thus, you do not need to specify the size when creating the component.

  • Determine the preferred size of the parent panel based on the components added to it. This will allow you to use the scrollbars correctly, as scrollbars can be added / removed as needed. Therefore, you need to determine how to work with drag and drop. That is, you can drag a component beyond the current border of the panel. If so, the preferred panel size should automatically increase.

Is there an already implemented LayoutManager that allows absolute component positioning

I played with a layout manager that is close to your needs. It was designed for use with the ComponentMover class from Moving Windows provided by trashgod.

Here is my test code for this class:

 import java.awt.*; import javax.swing.*; import javax.swing.border.*; /** */ public class DragLayout implements LayoutManager, java.io.Serializable { public DragLayout() { } /** * Adds the specified component with the specified name to the layout. * @param name the name of the component * @param comp the component to be added */ @Override public void addLayoutComponent(String name, Component comp) {} /** * Removes the specified component from the layout. * * @param comp the component to be removed */ @Override public void removeLayoutComponent(Component component) { } /** * Determine the minimum size on the Container * * @param target the container in which to do the layout * @return the minimum dimensions needed to lay out the * subcomponents of the specified container */ @Override public Dimension minimumLayoutSize(Container parent) { synchronized (parent.getTreeLock()) { return preferredLayoutSize(parent); } } /** * Determine the preferred size on the Container * * @param parent the container in which to do the layout * @return the preferred dimensions to lay out the * subcomponents of the specified container */ @Override public Dimension preferredLayoutSize(Container parent) { synchronized (parent.getTreeLock()) { return getLayoutSize(parent); } } /* * The calculation for minimum/preferred size it the same. The only * difference is the need to use the minimum or preferred size of the * component in the calculation. * * @param parent the container in which to do the layout */ private Dimension getLayoutSize(Container parent) { Insets parentInsets = parent.getInsets(); int x = parentInsets.left; int y = parentInsets.top; int width = 0; int height = 0; // Get extreme values of the components on the container for (Component component: parent.getComponents()) { if (component.isVisible()) { Point p = component.getLocation(); Dimension d = component.getPreferredSize(); x = Math.min(x, px); y = Math.min(y, py); width = Math.max(width, px + d.width); height = Math.max(height, py + d.height); } } // Width/Height is adjusted if any component is outside left/top edge if (x < parentInsets.left) width += parentInsets.left - x; if (y < parentInsets.top) height += parentInsets.top - y; // Adjust for insets width += parentInsets.right; height += parentInsets.bottom; Dimension d = new Dimension(width, height); return d; // return new Dimension(width, height); } /** * Lays out the specified container using this layout. * * @param target the container in which to do the layout */ @Override public void layoutContainer(Container parent) { synchronized (parent.getTreeLock()) { Insets parentInsets = parent.getInsets(); int x = parentInsets.left; int y = parentInsets.top; // Get X/Y location outside the bounds of the panel for (Component component: parent.getComponents()) { if (component.isVisible()) { Point location = component.getLocation(); x = Math.min(x, location.x); y = Math.min(y, location.y); } } x = (x < parentInsets.left) ? parentInsets.left - x : 0; y = (y < parentInsets.top) ? parentInsets.top - y : 0; // Set bounds of each component for (Component component: parent.getComponents()) { if (component.isVisible()) { Point p = component.getLocation(); Dimension d = component.getPreferredSize(); component.setBounds(px + x, py + y, d.width, d.height); } } }} /** * Returns the string representation of this column layout values. * @return a string representation of this layout */ public String toString() { return "[" + getClass().getName() + "]"; } public static void main( String[] args ) { ComponentMover cm = new ComponentMover(); cm.setEdgeInsets( new Insets(-100, -100, -100, -100) ); // cm.setEdgeInsets( new Insets(10, 10, 10, 10) ); cm.setAutoLayout(true); JPanel panel = new JPanel( new DragLayout() ); panel.setBorder( new MatteBorder(10, 10, 10, 10, Color.YELLOW) ); createLabel(cm, panel, "North", 150, 0); createLabel(cm, panel, "West", 0, 100); createLabel(cm, panel, "East", 300, 100); createLabel(cm, panel, "South", 150, 200); createLabel(cm, panel, "Center", 150, 100); JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add( new JScrollPane(panel) ); frame.pack(); frame.setLocationRelativeTo( null ); frame.setVisible( true ); } public static void createLabel(ComponentMover cm, JPanel panel, String text, int x, int y) { JLabel label = new JLabel( text ); label.setOpaque(true); label.setBackground( Color.ORANGE ); label.setLocation(x, y); panel.add( label ); cm.registerComponent( label ); } } 
  • For this layout, size is always considered preferred. You will need to change this. Size may be preferable if the size is (0, 0). When determining the preferred size of the parent container, you will also need to use the size of the component (not its preferred size).

  • The ComponentMover class can be customized so that you can drag comopnents outside the parent container or maintain the component inside the borders. If you allow components to be moved outside, the preferred size is automatically adjusted to take into account the new location of the component.

  • If you drag a component outside the top or left borders, then all components are shifted (right or down), make sure that the component does not have a negative location.

+3
source

Alternatively, consider also

+4
source

I assume that this will depend on the features of how you wanted him to behave.

The main reason the zero layout manager is discouraged is because the interfaces created using this can only be used in the size that they were designed because you cannot resize the user interface. If it suits you, use it.

Another option I know is the AbsoluteLayout with which Netbeans is distributed. You can get more information here: http://www.java-tips.org/other-api-tips/netbeans/can-i-distribute-absolutelayout-with-my-applica.html . I think this may be exactly what you are looking for, but, as you can see from this link, they recommend using a Null layout ... I do not think it matters a lot anyway.

If you need to allow users to determine how the component sizes will be resized, you end up with something like Netbeans Matisse form designer, which is likely to be redundant and will not amaze me so much fun :)

+1
source

The question is somewhat vague, so I might completely skip the point. I assume that you are looking for a layout that will allow you to use absolute positioning, but still allow you to resize the component and use all available space.

If you are manual coding, I have had success with MIGLayout ( http://www.miglayout.com/ ) and TableLayout (which is less absolute but very easy to use - http://java.sun.com/products/jfc/ tsc / articles / tablelayout / )

If you use any form constructor, using GroupLayout might be a good choice, but you don't want to manually code it. See This Question: GroupLayout: Is it Worth Learning?

0
source

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


All Articles