JSplitPane分隔符拖动无法使用复杂的布局

时间:2013-09-05 19:58:33

标签: java swing jsplitpane

我有一个带有JSplitPane的Java GUI程序划分内容。 JSplitPane的左侧是一个带有多个选项卡的JTabbedPane - 一个非常复杂的布局。当左侧达到一定程度的复杂性时,拖动分隔线以移动分隔线位置不再有效,但我仍然可以通过显式设置位置来移动分隔线。 (如果重要的话,我正在使用Nimbus LAF。)

它似乎不仅仅是左侧标签的数量。我在左侧包含的某些选项卡使其停止工作而其他选项卡正常。

有没有人碰到这个?

我能够通过在我的JSplitPane子类上添加一个黑客解决方法来解决它。

    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 这是SSCCE(下面)。当我运行它时,第一次将滑块向右拖动时,它会“捕捉”到长标签的末尾,然后保持固定。我相信它是由长标签引发的。如果我缩短标签,我会在滑块上获得更多的运动范围。那么这是一个错误,还是预期的行为?

    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;
    }

2 个答案:

答案 0 :(得分:3)

  

我花了很多时间试图达到一个目标   SSCCE但无法这样做

  • 请问什么? SSCCE最多5分钟


  • 现在还有两个问题

    1. 也有SplitPaneUI的定义,因为if (ui instanceof BasicSplitPaneUI) {可以返回false

    2. 描述了添加MouseMotionListener

    3. 的原因

EDIT_1st。

  

JSplitPane的左侧是一个带有多个标签的JTabbedPane    - 非常复杂的布局。当左侧达到一定程度的复杂性时,拖动分隔线以移动分隔线位置号   更长的工作,但我仍然可以通过明确设置移动分隔线   位置。

  

调整JSplitPane容器大小时的分配空间重量   拆分窗格控制分割时分隔符的行为   窗格已调整大小。如果重量为0,则给予所有额外空间   右或底组件。如果重量为1,则所有额外空间均为   给予左侧或顶部组件。权重.3指定   left或top组件获得额外空间的三分之一。重量   还决定了当分裂的大小时孩子们如何失去空间   窗格缩小了。例如,权重为0表示左侧或顶部   组件不会丢失任何空间。

     

重量也控制分隔线的起始位置。对于   例如,如果重量是.5,则分隔线位于中心。   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。

你忘了告诉我们在Nimbus中有分频器闪烁,而不是标准L&amp; 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;
    }
}

答案 1 :(得分:3)

这似乎是故意行为。在javax.swing.plaf.basic.BasicSplitPaneDivider.DragController的构造函数中找到以下代码:

minX = leftC.getMinimumSize().width;

然后在同一个班级

    /**
    * 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;
    }

因此,基本用户界面似乎不会让你拖动分隔线,使左侧小于最小尺寸。

在我的情况下,这种行为不符合我的需要,所以我的小解决方案是必要的。