如何在Java中正确设置最小大小?

14

我正在使用Java创建一个GUI应用程序,其中包含以下内容:

  • 一个JFrame,设置最小大小为(300,200)
  • 一个JSplitPane,其中包含:
    • 在左侧,有一个JScrollPane(包含一个JTree),最小大小为(100,0)(我只想限制宽度为200)
    • 在右侧,有一个JPanel,最小大小为(200,0)

在以下情况下,大小调整没有任何问题:

  • 将JSplitPane全部向左移动(到JScrollPane的最小大小),然后调整窗口大小
  • 仅调整窗口大小,到一定程度

当我将JSplitPane移得太靠右时,问题就出现了,在调整窗口大小时,JSplitPane右侧的JPanel未能遵循我设置的最小宽度。

我尝试在JScrollPane上设置最大宽度,但似乎没有任何帮助。

是否需要进行与最大大小相关的操作?或者也许有一种方法可以将监听器附加到面板中的一个以强制执行所需的行为?最终,我只想让JSplitPane中的右侧面板不少于200像素宽。

这里是一个演示我正在经历的问题的示例:

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;

public class ResizeTest
{
    private JFrame frame;
    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                try
                {
                    ResizeTest window = new ResizeTest();
                    window.frame.setVisible(true);
                }
                catch(Exception e)
                {
                    e.printStackTrace();
                }
            }
        });
    }
    public ResizeTest()
    {
        initialize();
    }
    private void initialize()
    {
        frame = new JFrame();
        frame.setMinimumSize(new Dimension(300, 200));
        frame.setBounds(100,100,450,300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new GridLayout(0, 1, 0, 0));

        JSplitPane splitPane = new JSplitPane();
        frame.getContentPane().add(splitPane);

        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setMinimumSize(new Dimension(100, 0));
        splitPane.setLeftComponent(scrollPane);

        JTree tree = new JTree();
        tree.setMinimumSize(new Dimension(100, 0));
        scrollPane.setViewportView(tree);

        JPanel panel = new JPanel();
        panel.setMinimumSize(new Dimension(200, 0));
        splitPane.setRightComponent(panel);
    }
}

更新:

很抱歉,我并没有完全理解提出的解决方案试图表达的重点,除了应该避免使用setPreferred()和setMinimum/Maximum()之外。

作为回应学习这一点的问题是:除了使用这些方法,我有哪些选项来限制JSplitPane分隔符MadProgrammer提到监听componentResized事件,但我需要更多的解释。我是在响应此事件时调用setDividerLocation()吗?

如果附加的问题在意义上是一个独立的StackOverflow问题,我提前道歉,如有必要可以在此发表另一篇并进行链接。

更新2:

不对用户选择如何调整窗口大小进行限制,并将右侧面板放在JScrollPane中,这是否是一个可行的选择?这看起来像是一种标准做法。


请修改您的问题,包含一个sscce展示你所描述的问题。 - trashgod
我意识到 panel.setMinimumSize 只是为了演示,但是 tree.setMinimumSize 是一个问题。在Java Swing中,我应该避免使用set(Preferred|Maximum|Minimum)Size方法吗 - trashgod
顺便说一句,sscce值得加1分。 - trashgod
2个回答

9
首先,方法setMinimumSize是向LayoutManager API提出的建议。这是一个可能会被忽略的建议。
为了能够支持这个功能,你需要使用类似ComponentListener来监听componentResized事件。
我认为最好的解决方案是使用实际上使用最小和最大大小约束的LayoutManager,比如GridBagLayout
将其用于“内容”面板,并将你的JSplitPane放置在其中(相应地设置其最小和最大大小),然后将“内容”面板添加到框架中。 更新 对不起,我可能漏掉了一些非常明显的东西,但我拼凑了一下这个小测试,希望它有一些有用的想法:P
public class TestFrameSize extends JFrame {

    public TestFrameSize() throws HeadlessException {

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(600, 600);
        setLocationRelativeTo(null);

        setMinimumSize(new Dimension(250, 250));

        JLabel left = new JLabel("Left");
        JLabel right = new JLabel("Right");

        Dimension pSize = new Dimension(100, 100);
        Dimension mSize = new Dimension(25, 100);

        left.setPreferredSize(pSize);
        left.setMinimumSize(mSize);
        right.setPreferredSize(pSize);
        right.setMinimumSize(mSize);

        JSplitPane pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right);

        JPanel content = new JPanel(new GridBagLayout());
        content.add(pane);

        setLayout(new BorderLayout());
        add(content);

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        new TestFrameSize().setVisible(true);

    }
}

“Window”从“Container”继承了“set/getMinimumSize”。虽然我很确定OP也想限制框架的大小,但使用“setMiniumumSize”将没有任何效果...我错了吗:P - MadProgrammer
哈,你知道吗,setMinimumSizeJFrame 上真的起作用了 :P - MadProgrammer
1
我对 JLabel#setPreferredSize() 感到谨慎。如果我理解正确,使用默认约束条件的 GridBagLayout 的行为类似于 GridLayout。在大多数平台上,文本可能不会被截断,但这是一个等待发生的问题。 - trashgod
1
是的,这是一个很好的观点(这只是一个演示)。就个人而言,我讨厌首选/最小/最大尺寸,如果可以避免的话。 - MadProgrammer
至少在macOS上,调用setMinimumSize()方法是限制用户可用的最小大小的唯一方法。如果您希望最小大小由布局管理器计算,则请参见我在此处发布的解决方案。 - Alan Snyder

3
在这个示例中,JSplitPane的内容首选大小最初设置为组件在getPreferredSize()中首选大小的小倍数。请注意,JSplitPane不会变得比由包含的Jlabel管理的面板的最小大小更小。

image


你的示例在Mac OS X上按预期工作,com.apple.laf.AquaLookAndFeel,其中分割窗格的UI代理在两个窗格上都强制执行最小值。 - trashgod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接