2

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

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

有没有人遇到过这个?

我可以通过在我的 JSplitPane 子类上添加一个 hack 变通方法来解决它。

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

更新这里是 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;
    }
4

2 回答 2

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

因此,基本 UI 似乎故意不允许您以使左侧小于其最小尺寸的方式拖动分隔线。

就我而言,这种行为不符合我的需求,所以我的小解决方法是必要的。

于 2013-09-05T21:34:34.843 回答
3

我花了很多时间试图达到拥有 SSCCE 的目的,但无法做到

.

  • 请问什么???SSCCE长达 5分钟


  • 现在还有两个问题

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

    2. 并说明为什么在其中添加了 MouseMotionListener


EDIT_1st。

JSplitPane 的左侧是一个带有许多选项卡的 JTabbedPane - 一个非常复杂的布局。当左侧达到一定复杂程度时,拖动分隔线移动分隔线位置不再起作用,但我仍然可以通过显式设置位置来移动分隔线。

调整 JSplitPane 容器大小时分配空间 拆分窗格的权重控制调整拆分窗格大小时分隔符的行为。如果权重为 0,则所有多余的空间都分配给右侧或底部组件。如果权重为 1,则所有额外空间都分配给左侧或顶部组件。0.3 的权重指定左侧或顶部组件获得三分之一的额外空间。权重还决定了当拆分窗格的大小减小时子级如何失去空间。例如,权重为 0 表示左侧或顶部组件不会丢失任何空间。

重量还控制着分隔线的起始位置。例如,如果权重为 0.5,则分隔线放置在中心。复制

// 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&F 引起的


在此处输入图像描述

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;
    }
}
于 2013-09-05T20:27:03.533 回答