Swing中JPanel的bounds与实际可视区域不匹配问题咨询
问题:Swing中
getBounds()返回范围与组件可视区域不匹配 我在开发一款展示大区域(如地图)的Swing应用,逻辑是用getBounds()返回的范围结合contains()方法,判断预创建的符号是否在可视区域内——不在的话就不在paintComponent里绘制。同时重写了getPreferredSize()给名为AreaWindow的JPanel设置初始尺寸。
当前遇到的问题:getBounds()返回的范围比实际可视区域小。复现代码里AreaWindow会出现空白区域;实际应用中,明明符号在可视区域内,contains()却返回false,导致符号不显示。观察发现缺失的区域刚好对应顶部按钮面板的大小,调整按钮面板行数,缺失区域也跟着变化。试过更换布局管理器没解决,用getSize()加左上角(0,0)是临时方案,担心后续出问题。
复现代码
Application类
package org.example; import java.awt.BorderLayout; import java.awt.GridLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class Application { public static void main(String[] args) { JFrame frame = new JFrame("Application"); // 调整行数,缺失区域会对应变化 JPanel buttonPanel = new JPanel(new GridLayout(2, 2)); buttonPanel.add(new JButton("1")); buttonPanel.add(new JButton("2")); buttonPanel.add(new JButton("3")); buttonPanel.add(new JButton("4")); AreaWindow mapArea = new AreaWindow(); frame.getContentPane().add(buttonPanel, BorderLayout.PAGE_START); frame.getContentPane().add(mapArea, BorderLayout.CENTER); frame.pack(); frame.setVisible(true); } }
AreaWindow类
package org.example; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import javax.swing.JPanel; public class AreaWindow extends JPanel { @Override public void setBounds(int x, int y, int width, int height) { super.setBounds(x, y, width, height); System.out.println("MapArea.setBounds: this bounds : " + this.getBounds()); } @Override public Dimension getPreferredSize() { return new Dimension(300, 300); } @Override public void paintComponent(Graphics graphicsObject) { super.paintComponent(graphicsObject); Graphics2D g2d = (Graphics2D) graphicsObject; g2d.setColor(Color.YELLOW); // 此处用getBounds()填充,仅用于演示问题 g2d.fill(getBounds()); g2d.setColor(Color.BLACK); g2d.drawString("Yellow is what getBounds() return < actual visible area", 10, 150); } }
解决方案
核心问题:getBounds()返回的是组件在父容器中的绝对坐标范围(比如你的AreaWindow在按钮面板下方,x=0、y=按钮面板高度),但paintComponent()使用的是组件自身的相对坐标系统(原点是组件左上角,即(0,0))。用getBounds()的矩形填充,相当于在组件的相对坐标里从父容器的位置开始画,自然会留出空白。
正确做法
要获取组件自身的可视区域,用以下两种方式:
getVisibleRect():返回组件自身坐标系下的可视矩形,x、y始终为0,宽高匹配组件实际显示尺寸new Rectangle(getSize()):利用组件自身坐标系原点为(0,0)的特性,直接通过尺寸生成矩形
修改后的AreaWindow代码
package org.example; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import javax.swing.JPanel; public class AreaWindow extends JPanel { @Override public void setBounds(int x, int y, int width, int height) { super.setBounds(x, y, width, height); System.out.println("MapArea.setBounds: this bounds : " + this.getBounds()); System.out.println("MapArea.setBounds: visible rect: " + this.getVisibleRect()); } @Override public Dimension getPreferredSize() { return new Dimension(300, 300); } @Override public void paintComponent(Graphics graphicsObject) { super.paintComponent(graphicsObject); Graphics2D g2d = (Graphics2D) graphicsObject; g2d.setColor(Color.YELLOW); // 使用getVisibleRect()获取自身可视区域 g2d.fill(getVisibleRect()); // 或者用new Rectangle(getSize())效果一致 // g2d.fill(new Rectangle(getSize())); g2d.setColor(Color.BLACK); g2d.drawString("Yellow now matches actual visible area", 10, 150); } }
符号可视性判断
如果要判断符号是否在可视区域内,直接用:
getVisibleRect().contains(symbolPoint)
注意:symbolPoint必须是基于AreaWindow自身坐标系的坐标。
内容的提问来源于stack exchange,提问作者ImpressiveStoneStatue
相关产品推荐
相关产品推荐

