Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: GUI и Java FX приложения > Почему setResizable() меняет размер фрейма!?


Автор: freshAngel 20.3.2009, 17:00
Привет, очень интересно почему происходит следующая вещь.
Простой пример программы. 
Код

 import javax.swing.*;   
 import javax.swing.JPanel;   
 import javax.swing.BoxLayout;   
 import javax.swing.border.LineBorder;   
 import javax.swing.border.EmptyBorder;   
 import javax.swing.border.CompoundBorder;   
 import javax.swing.border.TitledBorder;   
 import java.awt.*;   
    
 public class Main {   
    
     /**  
      * @param args the command line arguments  
      */   
    
     public static void main(String[] args) {   
         MyFrame frame = new MyFrame();   
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   
         frame.show();   
     }   
    
 } // End class Main   
    
 class MyFrame extends JFrame   
 {   
     public MyFrame()   
     {   
         setTitle("App");   
         MyPanel panel = new MyPanel();   
         setResizable(false);    
         setContentPane(panel);   
            
         System.out.println(getSize());   
         System.out.println(this.getPreferredSize());   
    
         pack();   
    
         System.out.println(getSize());   
         System.out.println(this.getPreferredSize());   
     }   
    
 } // End class MyFrame   
    
 class MyPanel extends JPanel   
 {   
     public MyPanel()   
         {   
 // Заполняем Panel   
          }   
 }   


Интересная вещь.
Если поставить setResizable(false) выдается одно значение размеров окна, в моем случае например:

java.awt.Dimension[width=374,height=296]
java.awt.Dimension[width=374,height=296]

А если setResizable(true) размер окна увеличивается:

java.awt.Dimension[width=384,height=306]
java.awt.Dimension[width=384,height=306]

Хотя само окно ни коем образом не меняется!
С чем это связано!?
Я конечно понимаю, что если использовать pack(), устанавливающий все размеры объектов на форме в PrefferedSize - то все сухо и прекрасно Smile
Но мне во первых хочется понять почему так, а во вторых я использую
setBounds() для установки размеров окна.

Автор: Turinets 21.3.2009, 09:31
Ну если приглядеться, то можно увидеть, что границы фрейма с изменяющимися размерами больше, чем у стационарного. Другими словами фрейм в Шубе будет больше чем в майке.

А вот что меня удивляет, так это то, что меняется и внутренняя часть:

Код

System.out.println(this.getContentPane().getSize());


А ведь размеры внутренней части ДОЛЖНЫ оставаться неизменными. В соседнем топике парень хотел сделать фрейи с заданными размерами внутренней части фрейма. У меня на винде такая вещь выходит: что при setResizeable(false) получается правильные размеры 200,200. А без него 202,202.
И вот это я совсем не понимаю.

Тебя не должны интересовать размеры фрейма, тебе нужны размеры именно внутренней части, а сам фрейм - это просто обводка вокрух них.

Автор: freshAngel 21.3.2009, 10:51
Цитата(Turinets @ 21.3.2009,  09:31)
Ну если приглядеться, то можно увидеть, что границы фрейма с изменяющимися размерами больше, чем у стационарного. Другими словами фрейм в Шубе будет больше чем в майке.

 smile 
Все - же хорошо, что есть pack()
Выход из положения придумал такой:
Код

class MyFrame extends JFrame
{
    public MyFrame()
    {
        setTitle("App");
        MyPanel panel = new MyPanel();
        this.setResizable(true); // Запрещаем менять размер
        setContentPane(panel);

     /*
    Если нужно жестко задать размеры окна, независимо от setResizable(), меняем желаемый размер.
    */
   
     //this.setPreferredSize(new Dimension(100,100));

    pack();

    System.out.println("Size "+panel.getSize().getWidth()+"  "+panel.getSize().getHeight());
    System.out.println("Size "+this.getContentPane().getSize().getWidth()+"  "+this.getContentPane().getSize().getHeight());
    System.out.println(getSize());
    System.out.println(this.getPreferredSize());
    }

} // End class MyFrame


А еще интересно почему вместо pack() не работает такая конструкция:
Код

setSize(this.getPreferredSize());


Автор: Turinets 21.3.2009, 11:07
А зачем тебе фиксированный размер окна?

Если нужен именно фиксированный размер фрейма, то тут кроме setSize() ничего и не нужно. pack() использовать смысла нет. Вроде если менять размер, то все внутреннии контейнеры выровняются "по линии" как надо (как компоновщик скажет), если надо вызвать самому, то getContentPane().doLayuot();

А что зачит не работает? Какой эффект должен быть по вашему, которого нет?

Автор: freshAngel 21.3.2009, 14:23
Цитата(Turinets @ 21.3.2009,  11:07)
А что зачит не работает? Какой эффект должен быть по вашему, которого нет?

Почему pack() != setSize(this.getPreferredSize());
Ведь это одно и тоже.

Что касается фиксированного размера фрейма, тут тоже странно.
Например, setSize(200,200) при setResizable(true) дает лишние отступы примерно в 2px по краям фрейма. Хотя я задал фиксированный размер!

При использовании pack(), размер фрейма автоматически подстраивается под нужный. 

Автор: Turinets 21.3.2009, 17:03
А разве это должно быть одним и темже?

getPrefferedSize() даёт установленные тобой  "Предпочтительный" размер. pack() опрашивает внутренние контейнеры и на основании их предпочтительных размеров (или минимальных точно не помню) будет и подгоняться внешний компонент. Т.е. если у тебя предпочтительный размер фрейма 300,300 , а у панели предпочтительный 400,400 , то pack()  сделает размеры примерно 400,400, а вот setSize(getPrefferedSize()) сделает размеры близкие к 300,300.

pack() - это очень хитрая вещь. Согласись, что "подстроить под нужный" двумя строчками кода нельзя. Там хитрый алгоритм. pack() старается сжать внешние контейнеры исходя из размеров внутренних.

Автор: freshAngel 21.3.2009, 18:39
Цитата(Turinets @ 21.3.2009,  17:03)
 Т.е. если у тебя предпочтительный размер фрейма 300,300 , а у панели предпочтительный 400,400 , то pack()  сделает размеры примерно 400,400, а вот setSize(getPrefferedSize()) сделает размеры близкие к 300,300.

Хмм.
А разве размер фрейма не должен принимать предпочтительные размеры панели установленной в него методом setContentPane()
Тогда почему не работает такая конструкция:

setSize(panel.getPrefferedSize()) != this.pack();

setSize() - в данном случае содержит именно предпочтительные размеры панели.

Автор: Turinets 21.3.2009, 20:45
Пусть ты сделал так:

panel.setPreferredSize(new Dimension(300,300));

Теперь если Ты сделаешь так:

frame.setSize(panel.getPreferredSize())

то фрейм примет размеры (300,300), а если так:

frame.pack()

фрейм станет скажем (306, 326).

Код

import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class AlfaFrame {

    public static void main(String[] args) {
        JFrame frame = new JFrame("Sample");
        JPanel panel = new JPanel() {
        };

        panel.setPreferredSize(new Dimension(300, 300));
        frame.getContentPane().add(panel);

        frame.setResizable(false);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        System.out.println("Size panel " + panel.getSize().getWidth() + "  " + panel.getSize().getHeight());
        System.out.println("Size frame " + frame.getSize().getWidth() + "  " + frame.getSize().getHeight());
        System.out.println("setSize");
        
        try {
            Thread.sleep(2000);
        } catch (InterruptedException ex) {
        }
        frame.setSize(panel.getPreferredSize());

        System.out.println("Size panel " + panel.getSize().getWidth() + "  " + panel.getSize().getHeight());
        System.out.println("Size frame " + frame.getSize().getWidth() + "  " + frame.getSize().getHeight());
        System.out.println("Size pane " + frame.getContentPane().getSize().getWidth() + "  " + frame.getContentPane().getSize().getHeight());
    }
}


У меня этот код выдает:
Код

Size panel 300.0  300.0
Size frame 306.0  327.0
setSize
Size panel 294.0  273.0
Size frame 300.0  300.0
Size pane 294.0  273.0



Из чего видим, что  в первом случае pack() ОБВОРАЧИВАТ панель с размерами, а во втором случае сам принимает такие размеры, из-за чего внутренней панели приходиться немного уменьшется.

Пойми, что сам фрейм имеет не нулевую толщину границ, например 306 получается путём добавление к 300 пикселам панели 2 границы по 3 пиксела с двух сторон, а 327 получается потому, что у фрейма есть вверху TitleBar. В любом случае Размеры самого фрейма будут больше, чем размеры внутренней панели. и они отличаются на толщину гранищы. Размер фрейма = размер левой границы + размер панели + размер правой границы. Т.е. размер фрейма != размеру панели и это очевидно.

Точно так же, как обхват талии девушки в шубе будет больше, чем без шубы, потому что сама шуба имеет не нулевую толщину.

Если ты про это. 
Предположим талия у КАТИ условно 60 см. ШУБА.pack() придаст шубе такой размер, который удобен для девушки, т.е. 60см+5см = 65см. А ШУБА.setSize(КАТЯ.getPreferredSize()) заставит Катю немного похудеть.

Автор: freshAngel 21.3.2009, 23:29
Цитата(Turinets @ 21.3.2009,  20:45)
Точно так же, как обхват талии девушки в шубе будет больше, чем без шубы, потому что сама шуба имеет не нулевую толщину.

Если ты про это. 
Предположим талия у КАТИ условно 60 см. ШУБА.pack() придаст шубе такой размер, который удобен для девушки, т.е. 60см+5см = 65см. А ШУБА.setSize(КАТЯ.getPreferredSize()) заставит Катю немного похудеть.

Пример с Катей удался  smile 
Проверил, осознал!
Спасибо.

Если касаться основного вопроса, то получается setResizable(true) либо setResizable(false), дополнительно увеличивает либо уменьшает границы фрейма соотвественно!?

Цитата(Turinets @ 21.3.2009,  09:31)

Ну если приглядеться, то можно увидеть, что границы фрейма с изменяющимися размерами больше, чем у стационарного. Другими словами фрейм в Шубе будет больше чем в майке.


Понял!

Спасибо большое, разобрался!  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)