在 JDialog 上强制执行隐式最小大小?

Enforcing an implicit minimum size on a JDialog?

问题

我有一个应用程序模式 JDialog,我希望它有一个强制的最小尺寸(即 OS 阻止用户使 window 小于最小尺寸).但是 window 应该仍然可以调整大小(即 setResizable(false) 不是一个选项)。优选地,应隐式定义强制的最小大小(即由子组件的最小大小动态确定,而不是使用 setMinimumSize)

显式设置的固定大小

我 运行 遇到的问题是,如果我没有通过 setMinimumSizeJDialog 上明确设置最小大小,OS不会强制执行。因此,即使 JDialog 隐含地知道在任何给定时间使用的正确最小大小,除非我调用 dlg.setMinimumSize(dlg.getMinimumSize()) 之类的东西,否则不会强制执行该大小。请参阅下面的 SSCCE。

在许多情况下,在打开对话框之前明确设置最小尺寸就足够了。但是,有时我会遇到这样一种情况,即在对话框打开时隐式最小大小可能会发生变化,例如可以从对话框中动态添加或删除子组件。如果我在对话框上设置了一个明确的最小尺寸,这个尺寸对于新布局来说可能不够大。

有什么方法可以配置 JDialog 以强制执行对话框的隐式最小大小?如果没有,是否有其他一些优雅的方法可以在打开的对话框上强制动态更改最小大小?

SSCCE

在这个 SSCCE 中,目标是创建一个不能小于 300x300 像素的对话框。只有明确设置最小大小才能实现此目标。

public class SSCCE {
    public static void main(String[] args) {
        JDialog dlg = new JDialog(null, ModalityType.APPLICATION_MODAL);
        dlg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);

        JPanel pnl = new JPanel(new BorderLayout());
        pnl.add(new JLabel("300x300"), BorderLayout.CENTER);

        // The panel is given a hard-coded minimum size just to make the
        // problem easier to see
        pnl.setMinimumSize(new Dimension(300,300));

        dlg.add(pnl);

        System.out.println("Dialog minimum size: " + dlg.getMinimumSize());
        // Minimum size is not enforced by the OS without this call
        dlg.setMinimumSize(dlg.getMinimumSize());
        System.out.println("Dialog minimum size: " + dlg.getMinimumSize());

        dlg.pack();
        dlg.setVisible(true);
    }
}

显式 setMinimumSize 调用:

没有显式 setMinimumSize 调用:

两种情况下的输出:

Dialog minimum size: java.awt.Dimension[width=300,height=300]
Dialog minimum size: java.awt.Dimension[width=300,height=300]

它的价值 - 我在 Windows 8.1 和 jdk1.8.0_91.

上观察到了这一点

However, this is less than ideal because it causes the minimum dialog size to be fixed

是的,您不应该对值进行硬编码。

您可以将面板的 getMinimumSize() 方法重写为:

  1. 只是 return 首选尺寸,或者
  2. return 首选尺寸的一些比例。

编辑;

is there some other elegant way to allow for a dynamically changing minimum size on an open dialog?

您可以在面板中添加 AncestorListenerancestorAdded 事件是在将面板添加到可见的 window 时生成的(因此基本上该事件是在对话框上的 setVisible() 之后生成的)。然后你可以使用 SwingUtilities.windowForComponent(...) 方法来获取面板的 window 。然后你可以在对话框中调用 setMinimumSize()。

检查代码中的注释。这里没有神奇的数字!

import java.awt.*;
import java.awt.Dialog.ModalityType;
import javax.swing.*;

public class SSCCE {
    public static void main(String[] args) {
        JDialog dlg = new JDialog(null, ModalityType.APPLICATION_MODAL);
        dlg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);

        JPanel pnl = new JPanel(new BorderLayout());
        pnl.add(new JLabel("As big as needed"), BorderLayout.CENTER);
        //pnl.setMinimumSize(new Dimension(300,300));
        dlg.add(pnl);

        System.out.println("Dialog minimum size: " + dlg.getMinimumSize());
        dlg.pack(); // make the dialog as large as needed to display content
        // Minimum size is not enforced by the OS without this call
        dlg.setMinimumSize(dlg.getPreferredSize());
        System.out.println("Dialog minimum size: " + dlg.getMinimumSize());

        dlg.setVisible(true);
    }
}

输出

Dialog minimum size: java.awt.Dimension[width=97,height=16]
Dialog minimum size: java.awt.Dimension[width=113,height=55]

我遇到了同样的问题,这就是我使用的代码:

addComponentListener(new ComponentAdapter() {
    @Override
    public void componentResized(ComponentEvent e) {
        Dimension size = getSize();
        
        if( size.getWidth() <= getMinimumSize().getWidth() || size.getHeight() <= getMinimumSize().getHeight() ) {
            int width = (int) (getMinimumSize().getWidth() + 2);
            int height = (int) (getMinimumSize().getHeight() + 2);
            
            setSize( new Dimension( width, height ) );
        }
    }
});