getPreferredSize()仅在pack()之后调用两次

时间:2013-04-01 19:15:42

标签: java swing jframe jpanel preferredsize

为什么getPreferredSize()仅在pack()上调用JFrame时被调用两次,如下例所示:

public class PackTest {
    static JFrame f = new JFrame();
    @SuppressWarnings("serial")
    public static void main(String[] args) {
        f.add(new JPanel() {
            int i = 0;
            @Override
            public Dimension getPreferredSize() {
                System.out.println("getPreferredSize() called");
                if(i++ >= 2)
                    return new Dimension(200, 200); // This is never returned
                else
                    return new Dimension(100, 100);
            }
        });
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);
        for(int i = 0; i < 10; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch(InterruptedException e) {}
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    System.out.println("Calling pack()");
                    f.pack();
                }
            });
        }
    }
}

似乎getPreferredSize()只有在不断返回不同的东西时才被调用(即如果每次返回不同的维度,它将在示例中被调用10次)。为什么Swing会这样做,以及如何让pack()正确调整JFrame的大小?

2 个答案:

答案 0 :(得分:2)

尝试重新验证您的JPanel,让它调用它的preferredSize:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class PackTest {

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }

   public static void createAndShowGui() {
      final JFrame f = new JFrame();
      final JPanel panel = new JPanel() {
         int i = 0;

         @Override
         public Dimension getPreferredSize() {
            System.out.println("getPreferredSize() called");
            if (i++ >= 2)
               return new Dimension(200, 200); // This is never returned
            else
               return new Dimension(100, 100);
         }
      };
      f.add(panel);
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      f.pack();
      f.setVisible(true);

      int delay = 1000;
      new Timer(delay, new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent arg0) {
            System.out.println("Calling pack()");
            panel.revalidate();
            f.pack();
         }
      }).start();
   }
}

顺便说一句,您需要确保使用真实的代码,您可以轻松地遵守Swing线程规则。

答案 1 :(得分:2)

当父容器调整大小或重新生效时,始终会调用

getPreferredSize()。无论此方法返回的Dimension值是什么,它都会对组件强制执行固定大小(如果被覆盖),无论窗口大小和其他组件如何,都不应更改。