Question

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;
    }
Was it helpful?

Solution 2

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.

OTHER TIPS

I spent quite a bit of time trying to get to the point of having a SSCCE but was unable to do so

.

  • please what??? an SSCCE up to 5minutes


  • now there are still two questions

    1. is there definition for SplitPaneUI too, because if (ui instanceof BasicSplitPaneUI) { can returns pretty the false

    2. with description for why reason in there added MouseMotionListener


EDIT_1st.

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.

Distributing Space When a JSplitPane Container Is Resized The weight of a split pane controls the behavior of the divider when the split pane is resized. If the weight is 0, all extra space is given to the right or bottom component. If the weight is 1, all extra space is given to the left or top component. A weight of .3 specifies that the left or top component gets one-third of the extra space. The weight also determines how the children lose space when the size of the split pane is reduced. For example, a weight of 0 means that the left or top component does not lose any space.

The weight also controls the starting location of the divider. For example, if the weight is .5, the divider is placed in the center. COPY

// Create a left-right split pane
JSplitPane pane = new JSplitPane(
     JSplitPane.HORIZONTAL_SPLIT, leftComponent, rightComponent);

// Get current weight
double weight = pane.getResizeWeight();    // 0.0 by default

// Keep the size of the right component constant
weight = 1D;
pane.setResizeWeight(weight);

// Split the space evenly
weight = .5D;
pane.setResizeWeight(weight);

EDIT_2nd.

you forgot to tell us that in Nimbus is there awfull flickering with divider, not caused with rest of Standard L&Fs


enter image description here

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;

public class JSplitPaneToy {

    private JSplitPane sp;

    public JSplitPaneToy() {
        sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, makePanel(), makePanel());
        /*SplitPaneUI ui = sp.getUI();
         if (ui instanceof BasicSplitPaneUI) {
         ((BasicSplitPaneUI) ui).getDivider().setBorder(null);
         }*/
        BasicSplitPaneUI l_ui = (BasicSplitPaneUI) sp.getUI();
        BasicSplitPaneDivider l_divider = l_ui.getDivider();
        l_divider.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                Dimension l_pane_size = sp.getSize();
                if (sp.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
                    int l_new_loc = sp.getDividerLocation() + e.getX();
                    if (l_new_loc >= 0 && l_new_loc <= l_pane_size.width) {
                        sp.setDividerLocation(l_new_loc);
                    }
                } else {
                    int l_new_loc = sp.getDividerLocation() + e.getY();
                    if (l_new_loc >= 0 && l_new_loc <= l_pane_size.height) {
                        sp.setDividerLocation(l_new_loc);
                    }
                }
            }
        });
        sp.setBorder(BorderFactory.createEmptyBorder());
        /*sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, makePanel(), sp);
         ui = sp.getUI();
         if (ui instanceof BasicSplitPaneUI) {
         ((BasicSplitPaneUI) ui).getDivider().setBorder(null);
         }
         sp.setBorder(BorderFactory.createEmptyBorder());
         sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, makePanel(), sp);
         ui = sp.getUI();
         if (ui instanceof BasicSplitPaneUI) {
         ((BasicSplitPaneUI) ui).getDivider().setBorder(null);
         }
         sp.setBorder(BorderFactory.createEmptyBorder());
         sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, makePanel(), sp);
         ui = sp.getUI();
         if (ui instanceof BasicSplitPaneUI) {
         ((BasicSplitPaneUI) ui).getDivider().setBorder(null);
         }
         sp.setBorder(BorderFactory.createEmptyBorder());*/
        JFrame frame = new JFrame("JSplitPane Toy");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(sp);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new JSplitPaneToy();
            }
        });
    }

    private JScrollPane makePanel() {
        JScrollPane pane = new JScrollPane(new JTable(
                new Object[][]{{0, 1, 2}, {1, 2, 3}, {2, 3, 4}}, new Object[]{1, 2, 3}) {
        });
        pane.setPreferredSize(new Dimension(200, 100));
        return pane;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top