如何在调整JComponent大小时保持其中心点位置不变
核心计算逻辑
要保证调整尺寸时组件中心点固定,只需提前记录初始状态下的固定中心点坐标,调整后用中心点反推新的左上角坐标即可,计算公式如下:
- 初始固定中心点:
fixedCx = 初始x坐标 + 初始宽度 / 2,fixedCy = 初始y坐标 + 初始高度 / 2 - 调整尺寸后新的左上角坐标:
newX = fixedCx - 新宽度 / 2,newY = fixedCy - 新高度 / 2
具体实现步骤
- 组件初始化完成后,提前计算并存储固定的中心点坐标,不要在每次尺寸调整时动态计算当前中心点,否则会出现累计偏移
- 每次触发滑块调整事件时,先计算调整后的新宽度、新高度
- 用上述公式计算新的左上角x、y坐标
- 调用
setBounds()方法一次性更新组件的坐标和尺寸,不要分开调用setSize()和setLocation(),避免出现闪烁错位
适配修改后的代码
你原有代码存在两个问题:一是滑块的最大最小值配置错误导致无法拖动,二是仅更新尺寸没有同步调整坐标,以下是修改后的核心逻辑(仅列出JButtonExperiments的Print方法,其余代码保持不变即可):
class JButtonExperiments { public static void Print() { JFrame frame = new JFrame(); frame.setLayout(null); frame.setSize(1200, 1200); JButton B = new JButton("w"); int initialWidth = 160; int initialHeight = 160; B.setBounds(600, 600, initialWidth, initialHeight); // 存储固定的中心点坐标,后续调整尺寸时不会变更 int fixedCx = B.getX() + initialWidth / 2; int fixedCy = B.getY() + initialHeight / 2; B.setText(new Scanner(System.in).nextLine()); frame.add(B); // 修正滑块构造参数:顺序为方向、最小值、最大值、初始值 JSlider widthSlider = new JSlider(SwingConstants.VERTICAL, 0, 400, 0); JSlider heightSlider = new JSlider(SwingConstants.VERTICAL, 0, 400, 0); widthSlider.setLocation(200, 600); JLabel widthBox = new JLabel("Width"); widthBox.setBounds(20, 500, 120, 120); heightSlider.setLocation(1000, 600); JLabel heightBox = new JLabel("Height"); heightBox.setBounds(1100, 500, 120, 120); widthSlider.setSize(100, 600); heightSlider.setSize(100, 600); frame.add(widthBox); frame.add(heightBox); frame.setVisible(true); AtomicInteger counter = new AtomicInteger(); B.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { counter.getAndIncrement(); if(counter.get() == 1) { frame.add(widthSlider); frame.add(heightSlider); frame.repaint(); } if(counter.get() == 3) { widthSlider.addChangeListener(E -> { int newWidth = initialWidth + widthSlider.getValue(); int newHeight = initialHeight + heightSlider.getValue(); int newX = fixedCx - newWidth / 2; int newY = fixedCy - newHeight / 2; B.setBounds(newX, newY, newWidth, newHeight); } ); heightSlider.addChangeListener(E -> { int newWidth = initialWidth + widthSlider.getValue(); int newHeight = initialHeight + heightSlider.getValue(); int newX = fixedCx - newWidth / 2; int newY = fixedCy - newHeight / 2; B.setBounds(newX, newY, newWidth, newHeight); } ); } } }); } }
注意事项
- 这里采用「初始宽高+滑块值」计算新尺寸,比每次叠加当前尺寸更稳定,不会出现累计误差
- 必须一次性调用
setBounds更新坐标和尺寸,分开调用会导致组件先拉伸再移动,出现肉眼可见的闪烁 - 如果后续要修改按钮初始位置,只需要调整
setBounds的初始参数,中心点会自动计算无需手动修改
内容的提问来源于stack exchange,提问作者TheGuradian
相关产品推荐
相关产品推荐

