I have a Java GUI program with a JSplitPane dividing the content. The left side of the JSplitPane is a JTabbedPane with a number of tabs - a very complex layout. When the left side reaches a certain level of complexity, dragging the divider to move the divider location no longer works, but I can still move the divider by explicitly setting the location. (If it matters, I am using Nimbus LAF.)
It doesn't seem to be just the number of tabs on the left. Certain tabs that I include on the left make it stop working and others are OK.
Has anyone ever run into this?
I was able to work around it by adding a hack workaround method on my JSplitPane subclass.
public void enableDividerWorkaround() {
javax.swing.plaf.basic.BasicSplitPaneUI l_ui = (javax.swing.plaf.basic.BasicSplitPaneUI) getUI();
BasicSplitPaneDivider l_divider = l_ui.getDivider();
l_divider.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
Dimension l_pane_size = getSize();
if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
int l_new_loc = getDividerLocation() + e.getX();
if (l_new_loc >= 0 && l_new_loc <= l_pane_size.width) {
setDividerLocation(l_new_loc);
}
} else {
int l_new_loc = getDividerLocation() + e.getY();
if (l_new_loc >= 0 && l_new_loc <= l_pane_size.height) {
setDividerLocation(l_new_loc);
}
}
}
});
}
UPDATE Here is the SSCCE (below). When I run this, the first time I drag the slider to the right, it "snaps" to the end of the long label and then remains fixed there. I believe it is triggered by the long label. If I shorten the label, I get more range of motion on the slider. So is it a bug, or the intended behavior?
public class SplitPaneTest extends javax.swing.JFrame {
public SplitPaneTest() {
initComponents();
}
private void initComponents() {
jSplitPane1 = new javax.swing.JSplitPane();
jLabel1 = new javax.swing.JLabel();
jPanel1 = new javax.swing.JPanel();
jLabel2 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jSplitPane1.setDividerLocation(450);
jSplitPane1.setName("jSplitPane1");
jLabel1.setText("right side");
jLabel1.setName("jLabel1");
jSplitPane1.setRightComponent(jLabel1);
jPanel1.setName("jPanel1");
jLabel2.setText("left side asd adsf asdf asdf asdf sadf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdfa end");
jLabel2.setName("jLabel2");
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel2)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel2)
.addContainerGap(420, Short.MAX_VALUE))
);
jSplitPane1.setLeftComponent(jPanel1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jSplitPane1)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jSplitPane1)
);
pack();
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new SplitPaneTest().setVisible(true);
}
});
}
protected javax.swing.JLabel jLabel1;
protected javax.swing.JLabel jLabel2;
protected javax.swing.JPanel jPanel1;
protected javax.swing.JSplitPane jSplitPane1;
}
This seems to be intentional behavior. Found the following code in the constructor of javax.swing.plaf.basic.BasicSplitPaneDivider.DragController:
minX = leftC.getMinimumSize().width;
then later on in that same class
/**
* Returns the new position to put the divider at based on
* the passed in MouseEvent.
*/
protected int positionForMouseEvent(MouseEvent e) {
int newX = (e.getSource() == BasicSplitPaneDivider.this) ?
(e.getX() + getLocation().x) : e.getX();
newX = Math.min(maxX, Math.max(minX, newX - offset));
return newX;
}
So it appears that the basic UI intentionally doesn't let you drag the divider in such a way as to make the left side smaller than its minimum size.
In my case, that behavior doesn't fit my needs, so my little workaround is necessary.