【问题标题】:JScrollPane minimum width inside JSplitPaneJScrollPane 内 JSplitPane 的最小宽度
【发布时间】:2021-07-10 10:28:58
【问题描述】:

我正在尝试JSplitPane 与几个可并排滚动的JTables。
但是,我正在尝试一种行为,其中JScrollPane 被缩小太多,根据 gif。
请注意左侧组件,除了具有最小width250px 之外,它还在继续缩小。

相关代码是

final var objetsTable = new JTable();
final var objectsScrollPane = new JScrollPane(objetsTable);
objectsScrollPane.setMinimumSize(new Dimension(250, 0));
objectsScrollPane.setPreferredSize(new Dimension(400, 300));

final var stepsTable = new JTable();
final var stepsScrollPane = new JScrollPane(stepsTable);
stepsScrollPane.setMinimumSize(new Dimension(150, 0));
stepsScrollPane.setPreferredSize(new Dimension(200, 300));

final var splitPane = new JSplitPane();
splitPane.setLeftComponent(objectsScrollPane);
splitPane.setRightComponent(stepsScrollPane);
splitPane.setResizeWeight(1.0);

在这种情况下,如何避免 JScrollPanes 缩小太多?

【问题讨论】:

  • 当左右组件都满足其最小尺寸并且用户不断缩小时,您希望发生什么?
  • @gthanop 我希望 JFrame(或至少外部组件)停止收缩。
  • 然后设置JFrame的最小尺寸。这将使用户无法继续缩小。
  • @gthanop 确定这是最简单的方法。但我不喜欢为最外层组件设置固定大小的想法。它应该基于包含轻量级组件。

标签: java swing jscrollpane jsplitpane


【解决方案1】:

JSplitPane 上调用的getMinimumSize 返回一个大小,该大小实际上考虑了其左右Components 的最小大小,加上分隔符大小。因此,可能解决您的问题的一种方法是让您的JSplitPane 实现Scrollable(以使其尊重自身的最小大小)并将其添加到JScrollPane。这样,您可以确保遵守最小尺寸,并且当用户继续缩小 Scrollable JSplitPane 超过其最小尺寸时,将显示滚动条。

这是一些工作代码:

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Rectangle;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JViewport;
import javax.swing.Scrollable;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;

public class Main {
    
    private static class MyScrollableSplitPane extends JSplitPane implements Scrollable {
        
        private int maxUnitIncrement = 10;
        
        public void setMaxUnitIncrement(final int pixels) {
            maxUnitIncrement = pixels;
        }
        
        public int getMaxUnitIncrement() {
            return maxUnitIncrement;
        }
        
        /**
         * This is being constantly checked by the scroll pane instead of the
         * getPreferredScrollableViewportSize...
         */
        @Override
        public Dimension getPreferredSize() {
            final Dimension minSz = getMinimumSize(),
                            curSz = getSize();
            curSz.width = Math.max(curSz.width, minSz.width);
            curSz.height = Math.max(curSz.height, minSz.height);
            return curSz;
        }
        
        /**
         * This is only checked once (at the beginning).
         */
        @Override
        public Dimension getPreferredScrollableViewportSize() {
            return super.getPreferredSize();
        }

        /**
         * Source: https://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html .
         */
        @Override
        public int getScrollableUnitIncrement(Rectangle visibleRect,
                                              int orientation,
                                              int direction) {
            //Get the current position.
            int currentPosition;
            if (orientation == SwingConstants.HORIZONTAL) {
                currentPosition = visibleRect.x;
            } else {
                currentPosition = visibleRect.y;
            }

            //Return the number of pixels between currentPosition
            //and the nearest tick mark in the indicated direction.
            if (direction < 0) {
                int newPosition = currentPosition -
                                 (currentPosition / maxUnitIncrement)
                                  * maxUnitIncrement;
                return (newPosition == 0) ? maxUnitIncrement : newPosition;
            } else {
                return ((currentPosition / maxUnitIncrement) + 1)
                       * maxUnitIncrement
                       - currentPosition;
            }
        }

        /**
         * Source: https://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html .
         */
        @Override
        public int getScrollableBlockIncrement(Rectangle visibleRect,
                                               int orientation,
                                               int direction) {
            if (orientation == SwingConstants.HORIZONTAL) {
                return visibleRect.width - maxUnitIncrement;
            } else {
                return visibleRect.height - maxUnitIncrement;
            }
        }

        @Override
        public boolean getScrollableTracksViewportWidth() {
            final Container parent = getParent();
            return (parent instanceof JViewport) && (getMinimumSize().width < ((JViewport) parent).getWidth());
        }

        @Override
        public boolean getScrollableTracksViewportHeight() {
            final Container parent = getParent();
            return (parent instanceof JViewport) && (getMinimumSize().height < ((JViewport) parent).getHeight());
        }
    }
    
    private static void createAndShowGUI() {
        
        /*Since I don't add any Components to the 'left' and 'right' panels, I am going to set the
        preferred size of them. This is only for demonstrating the concept. Setting the minimum size
        though is somewhat required by the JSplitPane itself.*/
        
        final JPanel left = new JPanel();
        left.setMinimumSize(new Dimension(150, 100));
        left.setPreferredSize(new Dimension(200, 200));
        
        final JPanel right = new JPanel();
        right.setMinimumSize(new Dimension(300, 100));
        right.setPreferredSize(new Dimension(400, 200));
        
        final JSplitPane split = new MyScrollableSplitPane();
        split.setBorder(BorderFactory.createLineBorder(Color.CYAN.darker(), 3));
        split.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
        split.setLeftComponent(left);
        split.setRightComponent(right);
        
        final JFrame frame = new JFrame("MyScrollableSplitPane demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new JScrollPane(split));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(Main::createAndShowGUI);
    }
}

【讨论】:

  • 谢谢!我会尽快看看并尝试
  • 这个,加上ScrollPaneConstants.VERTICAL/HORIZONTAL_SCROLLBAR_NEVER 到外部滚动窗格,frame.setMinimumSize(split.getMinimumSize()) 得到我想要的结果。
  • 尝试添加我的两个编辑并查看结果。
  • 我很高兴你让它工作了。注意frame.setMinimumSize(split.getMinimumSize());:我认为框架的最小尺寸考虑了标题栏和窗口边框...
  • 是的,我注意到有些地方不完美,但我会解决的。
猜你喜欢
  • 1970-01-01
  • 2011-02-12
  • 2013-06-25
  • 2018-02-08
  • 2012-11-07
  • 2018-04-23
  • 2017-11-29
  • 1970-01-01
  • 2013-05-14
相关资源
最近更新 更多