swing组件通过setBounds设置位置不生效,最后一个加入容器的组件始终居中显示问题分析

个人博客:狐狸半面添的客栈

文章目录

  • 1.问题描述
  • 2.问题分析
  • 3.问题解决

1.问题描述

我们先看一段非常简单的代码来展示我们的问题:

import javax.swing.*;

/**
 * @author 狐狸半面添
 * @create 2023-09-19 1:26
 */
public class MyFrame extends JFrame {

    /**
     * 启动项目,创建容器
     */
    public static void main(String[] args) {
        new MyFrame();
    }

    public MyFrame() {
        // 初始化界面
        initJFrame();

        // 初始化图片
        initImage();

        // 设置窗体可见
        this.setVisible(true);
    }

    /**
     * 初始化界面/容器
     */
    private void initJFrame() {
        // 设置窗体宽高
        this.setSize(600, 600);
        // 设置标题
        this.setTitle("Demo");
        // 设置窗体居中
        this.setLocationRelativeTo(null);
        // 设置窗体关闭方式
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    /**
     * 初始化图片组件
     */
    private void initImage() {
        // 展示两张图片 0.jpg 和 1.jpg ,两张图片的宽高都是 105
        for (int i = 0; i < 2; i++) {
            // 创建一个管理容器
            JLabel jLabel = new JLabel(new ImageIcon("D:\\image\\" + i + ".jpg"));
            // 指定照片位置
            jLabel.setBounds(105 * i, 0, 105, 105);
            // 把管理容器加到界面当中
            this.getContentPane().add(jLabel);
        }
    }

}

我们运行期待的结果是两张图片在第一行依次排列,但是实际上的效果是:

  • 0.jpg 在 setBounds 设置的位置正确摆放;
  • 1.jpg 在布局页面的中央位置显示,setBounds 设置没有生效。

swing组件通过setBounds设置位置不生效,最后一个加入容器的组件始终居中显示问题分析_第1张图片

2.问题分析

默认情况下,JFrame 使用 BorderLayout 作为其内容面板的布局管理器。

JFrame 使用 BorderLayout 作为布局管理器的底层逻辑:

  1. 当内容面板添加多个组件时,它们将按照 BorderLayout 的规则进行排列。
  2. 对于 BorderLayout,默认情况下,只有 **中央位置(CENTER)**处的组件会填充整个可见区域。
  3. 而 BorderLayout 只允许一个组件占据中央位置,因此先加入进来的组件会有两种处理方式:
    • 如果设置了 setBounds(),则会放到设置的位置;
    • 如果没设置 setBounds(),则先加入的组件仍会留在中间位置,但会被后加入的组件所覆盖掉。

因此,这就解释了为什么我们最后一张图片没有按照设置的 setBounds 摆放,而是一直处于界面的正中央。因为 BorderLayout 布局是生效的,换句话说,BorderLayout 布局设置优先级高于 setBounds。

因此,如果我们想让我们的所有组件位置布局生效,或者说是最后一个组件的位置布局生效,就需要移除默认的 BorderLayout 布局管理器

3.问题解决

通过设置 setLayout(null),我们将 JFrame 的布局管理器设置为空,这意味着我们需要手动控制组件的位置和大小,而不是依赖于自动布局。这对于我们在 setBounds() 方法中直接设置组件的位置和大小非常有用。

我们修改“问题描述”中提供的代码的 initJFrame() 方法,只需要在方法中加一段移除布局管理器的设置即可:

// 移除默认的 BorderLayout 布局管理器
this.getContentPane().setLayout(null);

swing组件通过setBounds设置位置不生效,最后一个加入容器的组件始终居中显示问题分析_第2张图片

最终效果:
swing组件通过setBounds设置位置不生效,最后一个加入容器的组件始终居中显示问题分析_第3张图片

你可能感兴趣的:(#,java,swing,JFrame,BorderLayout)