Below is the code for a simple layout created using several nested JSplitPanes
.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
public class CDBurner extends JFrame {
private static final long serialVersionUID = -6027473114929970648L;
JSplitPane main, folder, rest;
JPanel centeral, folders, favourites, tasks;
JLabel label;
private CDBurner() {
super("Dan's CD Burner");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(1, 1));
getContentPane().setBackground(Color.black);
createLayout();
pack();
setMinimumSize(getSize());
setExtendedState(getExtendedState() | JFrame.MAXIMIZED_BOTH);
setVisible(true);
requestFocus();
}
private void createLayout() {
createPanels();
rest = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, centeral, tasks);
rest.setResizeWeight(1);
rest.setContinuousLayout(true);
rest.setOneTouchExpandable(true);
folder = new JSplitPane(JSplitPane.VERTICAL_SPLIT, favourites, folders);
folder.setResizeWeight(0.35);
folder.setContinuousLayout(true);
folder.setOneTouchExpandable(true);
main = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, folder, rest);
main.setResizeWeight(0);
main.setContinuousLayout(true);
main.setOneTouchExpandable(true);
getContentPane().add(main);
}
private void createPanels() {
createFolders();
createCenter();
createTaskSpool();
createFavourites();
}
private void createFolders() {
folders = new JPanel(new GridLayout(1, 1));
label = new JLabel("Folder");
folders.setMinimumSize(new Dimension(300, 100));
folders.add(label);
}
private void createCenter() {
centeral = new JPanel(new GridLayout(1, 1));
label = new JLabel("Central");
centeral.add(label);
centeral.setMinimumSize(new Dimension(300, 100));
}
private void createTaskSpool() {
tasks = new JPanel(new GridLayout(1, 1));
label = new JLabel("Task");
tasks.setMinimumSize(new Dimension(300, 100));
tasks.add(label);
}
private void createFavourites() {
favourites = new JPanel(new GridLayout(1, 1));
label = new JLabel("Fav");
favourites.setMinimumSize(new Dimension(300, 100));
favourites.add(label);
}
public static void main(String[] args) {
new CDBurner();
}
}
Due to the line rest.setResizeWeight(1);
you can drag the main (JSplitPane)
divider to the right and it will shrink the tasks JPanel
to the until both the JPanels
in rest
are the minimum size. However, if you try to do the opposite nothing happens. See images below to see problem.
If the gui looks like this, you can drag the main
divider.
And you will get the result of this.
However if it looks like this and you try to drag the rest
divider nothing happens.
This is because both sides of the rest JSplitPane
are already at their minimum size.
The Question
How can I make it so that when I drag the rest
divider it effects the main JSplitPane
so that both the operations shown in the images above are possible?
As far as I know the behaviour you describe is normal behaviour for divided views. Have a look on how the dividers of
professional applications like Eclipse behave.
Anyway I created a workaround for your desired behaviour by controlling the movements of your rest JSplitPane
divider programmatically.
You simply need to add these lines of code after creating your rest JSplitPane
in your createLayout()
method.
SplitPaneUI spui = rest.getUI();
if (spui instanceof BasicSplitPaneUI) {
((BasicSplitPaneUI) spui).getDivider().addMouseMotionListener(new MouseAdapter(){
@Override
public void mouseDragged(MouseEvent E){
int newPos = E.getPoint().x;
if(newPos < 0 && folder.getSize().width > 300 && centeral.getSize().width <= 300){
main.setDividerLocation(main.getDividerLocation() + newPos);
validate();
}
if(centeral.getSize().width > 300 && tasks.getSize().width > 300){
rest.setDividerLocation(rest.getDividerLocation() + newPos);
validate();
}
}
});
}
explanation:
In the first lines we take the UI object of the divider of JSplitPane
and add a custom MouseMotionListener
to it. We need the
UI object because the real JSplitPane
doesn't get any mouse events directly.
Inside the listener we override the mouseDragged
method and receive the actual X-position of the mouse while its dragging
the divider.
If its a negative value we are dragging the divider to the left. In this case we also want the main divider to move if
the center panel has already shrunk to its minium size of 300 and the left folder panel is still bigger than its minimum size.
The rest divider should be movable if central and the task panel on the right are still bigger than their minimum size of 300.
JLayer
JSplitPane.HORIZONTAL_SPLIT
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
public class CDBurner2 extends JFrame {
JSplitPane main, folder, rest;
JPanel centeral, folders, favourites, tasks;
JLabel label;
private CDBurner2() {
super("Dan's CD Burner");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
createLayout();
setExtendedState(getExtendedState() | JFrame.MAXIMIZED_BOTH);
setVisible(true);
}
private void createLayout() {
createPanels();
rest = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, centeral, tasks);
rest.setResizeWeight(1);
rest.setContinuousLayout(true);
rest.setOneTouchExpandable(true);
folder = new JSplitPane(JSplitPane.VERTICAL_SPLIT, favourites, folders);
folder.setResizeWeight(0.35);
folder.setContinuousLayout(true);
folder.setOneTouchExpandable(true);
main = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, folder, rest);
main.setResizeWeight(0);
main.setContinuousLayout(true);
main.setOneTouchExpandable(true);
//getContentPane().add(main);
getContentPane().add(new JLayer<JSplitPane>(
main, new SplitPaneDividerDragLayerUI()));
}
private void createPanels() {
createFolders();
createCenter();
createTaskSpool();
createFavourites();
}
private void createFolders() {
folders = new JPanel(new GridLayout(1, 1));
label = new JLabel("Folder");
folders.setMinimumSize(new Dimension(300, 100));
folders.add(label);
}
private void createCenter() {
centeral = new JPanel(new GridLayout(1, 1));
label = new JLabel("Central");
centeral.add(label);
centeral.setMinimumSize(new Dimension(300, 240));
centeral.setPreferredSize(new Dimension(600, 240));
}
private void createTaskSpool() {
tasks = new JPanel(new GridLayout(1, 1));
label = new JLabel("Task");
tasks.setMinimumSize(new Dimension(300, 240));
tasks.setPreferredSize(new Dimension(600, 240));
tasks.add(label);
}
private void createFavourites() {
favourites = new JPanel(new GridLayout(1, 1));
label = new JLabel("Fav");
favourites.setMinimumSize(new Dimension(300, 100));
favourites.add(label);
}
public static void main(String... args) {
EventQueue.invokeLater(() -> new CDBurner2());
}
}
class SplitPaneDividerDragLayerUI extends LayerUI<JSplitPane> {
private int dividerLocation;
private final Point startPt = new Point();
@Override public void installUI(JComponent c) {
super.installUI(c);
if (c instanceof JLayer) {
((JLayer) c).setLayerEventMask(
AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
}
@Override public void uninstallUI(JComponent c) {
if (c instanceof JLayer) {
((JLayer) c).setLayerEventMask(0);
}
super.uninstallUI(c);
}
@Override protected void processMouseEvent(
MouseEvent e, JLayer<? extends JSplitPane> l) {
super.processMouseEvent(e, l);
JSplitPane splitPane = l.getView();
Component c = e.getComponent();
if (e.getID() == MouseEvent.MOUSE_PRESSED && c instanceof BasicSplitPaneDivider) {
JSplitPane sp = (JSplitPane) SwingUtilities.getUnwrappedParent(c);
if (!splitPane.equals(sp) && sp.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
startPt.setLocation(SwingUtilities.convertPoint(c, e.getPoint(), sp));
dividerLocation = splitPane.getDividerLocation();
}
}
}
@Override protected void processMouseMotionEvent(
MouseEvent e, JLayer<? extends JSplitPane> l) {
super.processMouseEvent(e, l);
JSplitPane splitPane = l.getView();
Component c = e.getComponent();
if (e.getID() == MouseEvent.MOUSE_DRAGGED && c instanceof BasicSplitPaneDivider) {
JSplitPane sp = (JSplitPane) SwingUtilities.getUnwrappedParent(c);
if (!splitPane.equals(sp) && sp.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
Point pt = SwingUtilities.convertPoint(c, e.getPoint(), sp);
int delta = pt.x - startPt.x;
startPt.setLocation(pt);
if (delta < 0 && sp.getMinimumDividerLocation() == sp.getDividerLocation()) {
//System.out.println("delta: " + delta);
dividerLocation = Math.max(
splitPane.getMinimumDividerLocation(), dividerLocation + delta);
splitPane.setDividerLocation(dividerLocation);
EventQueue.invokeLater(() -> {
sp.setDividerLocation(sp.getMinimumDividerLocation());
});
}
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With