JFrame#setLayout(LayoutManager) 不工作。强制执行 getContentPane().setLayout(LayoutManager)

JFrame#setLayout(LayoutManager) not working. Forced to do getContentPane().setLayout(LayoutManager)

当 运行 实例化此 class 的代码时:

static final class MyFrame extends JFrame {
    private CardLayout layout = new CardLayout();

    public MyFrame() {
        setLayout(layout);
        System.out.println(getLayout());
    }
}

打印出来的结果是:

java.awt.BorderLayout[hgap=0,vgap=0]

这是 JFrame 的默认布局。布局没有改变。但是,如果我改变

setLayout(layout);

getContentPane().setLayout(layout)

getLayout() 将打印正确的布局。

MVCE:

未设置布局:

public class Main {
    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            MyFrame frame = new MyFrame();
            frame.setVisible(true);
        });
    }

    static final class MyFrame extends JFrame {
        private CardLayout layout = new CardLayout();

        public MyFrame() {
            setLayout(layout);
            System.out.println(getLayout());
        }
    }
}

设置布局:

public class Main {
    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            MyFrame frame = new MyFrame();
            frame.setVisible(true);
        });
    }

    static final class MyFrame extends JFrame {
        private CardLayout layout = new CardLayout();

        public MyFrame() {
            getContentPane().setLayout(layout);
            System.out.println(getLayout());
        }
    }
}

我觉得你漏掉了什么地方。这是在我的电脑上使用 and

的结果
setLayout(layout);
System.out.println(getContentPane().getLayout()); // CardLayout is printed
System.out.println(getLayout()); // BorderLayout is printed

getContentPane().setLayout(layout);
System.out.println(getContentPane().getLayout()); // CardLayout is printed
System.out.println(getLayout()); // BorderLayout is printed

为什么不总是打印 CardLayout?

因为,与 JFrame#setLayout(LayoutManager) 不同,JFrame#getLayout() 不会调用其 contentPane()

事实上,JFrame#getLayout() 实际上是从 Container#getLayout() 继承的,它将 return 来自实际组件的实际 LayoutManager(在这种情况下 JFrame 而不是 contentPane()).


JFrame#setLayout

Sets the LayoutManager. Overridden to conditionally forward the call to the contentPane. Refer to RootPaneContainer for more information.