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

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

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 设置没有生效。

image-20230919020129312

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);

image-20230919021028836

最终效果:
image-20230919021251116

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是谢添啊

感谢你的支持,我会继续加油的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值