Posted by Rob Camick on October 23, 2011
We have been taught that you should always use a layout manager to layout components on a container. But what about the times when you want the ability to randomly position components on a panel by dragging them with a mouse? Should we use a null layout or can we still use a layout manager?
To answer this question it is important to remember that a layout manager performs 3 different functions:
- set the location of the components in the container
- set the size of the components in the container
- calculate the preferred size of the container. The preferred size is important so you can pack() your frame or dialog. It is also important for any container that is added to a scroll pane. In order for the scrollbars to function properly, the preferred size must be calculated correctly.
When dragging components, it should be apparent that a layout manager should not override the location of the component. However, there is no reason that a layout manager could not set the size of the component and calculate the preferred size of the container.
DragLayout was designed to replace a null layout. It will respect the location of a component. By default it will use the preferred size of the component to determines its size. Finally, it will automatically calculate the preferred size of the Container.
An added feature of the DragLayout is that it will ensure that components cannot have a negative location. When a component is dragged outside the top/left edge of a container, its location will be adjusted such that it is placed within the border of the container. In addition all other components in the container will be adjusted to retain the same relative location to the moved component
DragLayout only has a single property:
- setUsePreferredSize – when true (default), the preferred size of the component is always used as the size of the component. When false, the preferred size is used as the size of the component only when the size is 0. Therefore you can manually set the initial size or change the size dynamically. This would be useful when you require the ability to manually resize components.
The DragLayout class is not responsible for doing the dragging of any component. The code you use to drag a component is responsible for invoking revalidate() on the component when the drag is finished. This will cause the layout manager to be invoked so the containers preferred size can be recalculated.
Usage of a DragLayout is straight forward:
JPanel dragPanel = new JPanel( new DragLayout() );
frame.add( new JScrollPane(dragPanel) );
The Webstart demo uses the ComponentMover class (see link below) to handle dragging of the components. The code allows you to move a component up to 100 pixels outside the bounds of the container at one time:
ComponentMover cm = new ComponentMover();
cm.setEdgeInsets( new Insets(-100, -100, -100, -100) );
The labels where then created with code something like:
JLabel north = new JLabel("North");
JLabel south = new JLabel("South");
The DragLayout class should be used any time you consider using a null layout. Even if you manually set the location and size of a component, you will still benefit from the calculation of the containers preferred size.