Налагане на косвен минимален размер на JDialog?

Въпрос

Имам модално приложение JDialog, което искам да има наложен минимален размер (т.е. операционната система не позволява на потребителя да направи прозореца по-малък от минималния размер). Но прозорецът все пак трябва да може да се променя размера (т.е. setResizable(false) не е опция). За предпочитане е наложеният минимален размер да бъде имплицитно дефиниран (т.е. динамично определен от минималните размери на дъщерните компоненти, а не фиксиран размер, зададен изрично с помощта на setMinimumSize)

Проблемът, с който се сблъсках, е, че изглежда, че ако не задам изрично минимален размер на JDialog чрез setMinimumSize, операционната система няма да го наложи. Така че въпреки че 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 повикване:

„Неправилно

Изход и в двата случая:

Минимален размер на диалоговия прозорец: java.awt.Dimension[width=300,height=300]
Минимален размер на диалоговия прозорец: java.awt.Dimension[width=300,height=300]

За какво си струва - наблюдавах това на Windows 8.1 с jdk1.8.0_91.


person Kevin K    schedule 19.10.2016    source източник
comment
диалог, който не може да бъде направен по-малък от 300x300 пиксела. Защо? И което е по-важно, защо диалоговият прозорец, за разлика от областта на съдържанието на диалоговия прозорец (панела)?   -  person Andrew Thompson    schedule 22.10.2016
comment
@AndrewThompson Размерът 300x300 е произволно избран за SSCCE. В SSCCE ръчно задавам това като минимален размер за JPanel, за да симулирам някакъв контрол или контейнер, който има присъщ минимален размер, като JLabel или JTable. Минималните размери се разпространяват нагоре през мениджърите на оформлението - тъй като панелът има минимален размер 300x300, диалоговият прозорец също трябва да има минимален размер 300x300. Но операционната система не налага това, освен ако изрично не задам минимален размер чрез извикване на JDialog.setMinimumSize().   -  person Kevin K    schedule 09.11.2016


Отговори (3)


Това обаче не е идеално, защото води до фиксиране на минималния размер на диалоговия прозорец

Да, не трябва да кодирате твърдо стойности.

Можете да замените метода getMinimumSize() на вашия панел, за да:

  1. просто върнете предпочитания размер, или
  2. върне някакво съотношение на предпочитания размер.

Редактиране;

има ли някакъв друг елегантен начин да се даде възможност за динамично променящ се минимален размер на отворен диалог?

Можете да добавите AncestorListener към вашия панел. Събитието ancestorAdded се генерира, когато панелът се добави към видим прозорец (така че основно събитието се генерира след setVisible() в диалоговия прозорец). След това можете да използвате метода SwingUtilities.windowForComponent(...), за да получите прозореца за панела. След това можете да извикате setMinimumSize() в диалоговия прозорец.

person camickr    schedule 19.10.2016
comment
Опитах да отменя getMinimumSize() на JPanel, няма значение. Твърдо кодираните стойности са само за краткост в SSCCE. JDialog знае правилния минимален размер, проблемът е, че не го налага, освен ако не е изрично зададен чрез dlg.setMinimumSize(...) - person Kevin K; 19.10.2016
comment
това е полезно, благодаря. Предполагам, че бих могъл също да използвам ContainerListener, за да отговоря, ако даден компонент е добавен/премахнат. - person Kevin K; 20.10.2016

Проверете коментарите в кода. Тук няма магическо число!

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]
person Andrew Thompson    schedule 20.10.2016
comment
Здравей Андрю, както споменах и на camickr, твърдо кодираният минимален размер на JPanel е само за краткост в SSCCE. Действителният ми въпрос е как да накарам операционната система да наложи имплицитния минимален размер на JDialog. Актуализирах въпроса си, за да стане по-ясно. - person Kevin K; 20.10.2016

Имах същия проблем и това е кодът, който използвам:

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 ) );
        }
    }
});
person Brad    schedule 01.05.2021