简体   繁体   中英

Enforcing an implicit minimum size on a JDialog?

Question

I have an application-modal JDialog which I want to have an enforced minimum size (ie the OS prevents the user from making the window any smaller than the minimum size). But the window should still be resizable (ie setResizable(false) is not an option). Preferably, the enforced minimum size should be implicitly defined (ie dynamically determined by the minimum sizes of the child components, and not a fixed size set explicitly using setMinimumSize )

The problem I've run into is that it seems if I don't explicitly set a minimum size on the JDialog via setMinimumSize , the OS will not enforce it. So even though the JDialog implicitly knows the correct minimum size to use at any given time, that size won't be enforced unless I call something like dlg.setMinimumSize(dlg.getMinimumSize()) . See the SSCCE below.

In many cases, explicitly setting the minimum size just before opening the dialog is sufficient. However, sometimes I have a situation where the implicit minimum size can change while the dialog is open, eg a child component may be dynamically added or removed from the dialog. And if I set an explicit minimum size on the dialog, that size may not be sufficiently large for the new layout.

Is there any way to configure a JDialog to enforce the implicit minimum size of the dialog? If not, is there some other elegant way to enforce a dynamically changing minimum size on an open dialog?

SSCCE

In this SSCCE, the goal is to create a dialog that cannot be made any smaller than 300x300 pixels. This goal is only met if the minimum size is explicitly set.

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

With explicit setMinimumSize call:

大小合适的 300x300 JDialog

Without explicit setMinimumSize call:

大小不合适的 JDialog

Output in both cases:

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

For what it's worth - I observed this on Windows 8.1 with jdk1.8.0_91.

Check comments in code. No magic number here!

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

Output

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

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

Yes you should not be hardcoding values.

You could override the getMinimumSize() method of your panel to:

  1. just return the prefeferred size, or
  2. return some ratio of the preferred size.

Edit;

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

You could add an AncestorListener to your panel. The ancestorAdded event is generated when the panel is added to a visible window (so basically the event is generated after the setVisible() on the dialog). Then you can use the SwingUtilities.windowForComponent(...) method to get the window for the panel. Then you can invoked the setMinimumSize() on the dialog.

I had the same issue, and that's the code i use:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM