Java中Frame切换为JFrame出现绘制残留问题及JPanel使用咨询
问题根因
你遇到的残影问题本质是不规范的Swing绘制写法导致的,在AWT Frame上没出问题只是两个组件库的绘制逻辑差异造成的巧合:
- AWT组件的默认重绘流程是:触发重绘时先调用
update()方法,用背景色填充整个组件区域清空旧内容,再调用paint()执行自定义绘制。哪怕你重写paint()不调用父类实现,清屏步骤已经在update里做完了,所以旧的坐标文字不会残留。 - Swing组件(包括JFrame)重写了这套逻辑,默认
update()会直接调用paint(),而paint()的默认实现会依次执行三个步骤:绘制组件本身、绘制边框、绘制所有子组件,其中就包含清空旧内容的逻辑。你直接重写JFrame的paint()方法且没有调用super.paint(g),等于跳过了所有默认绘制流程,既不会清空之前画的内容,还可能出现组件层级渲染错乱。 - 另外你代码里虽然创建了JPanel,但从来没把它添加到JFrame中,也没有把监听器绑定到有效组件上,自然达不到避开标题栏计算坐标的效果。
最简单的修复方案
不要重写JFrame的paint()方法,把自定义绘制逻辑放到JPanel上,这也是Swing官方推荐的标准写法,同时能自动解决标题栏计入坐标的问题——JPanel本身就是JFrame去掉标题栏的内容区域,点击坐标天然从JPanel左上角开始计算,不需要额外做坐标偏移。
修复后的可运行代码如下:
import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.awt.Color; public class Proj07Runner { Proj07Runner(){ System.out.println("Terminal text"); new GUI(); } // 补上原代码缺失的main入口 public static void main(String[] args) { new Proj07Runner(); } } // 自定义面板承载绘制逻辑,代替继承JFrame重写paint class MyPanel extends JPanel { int clickX = -1; int clickY = -1; @Override protected void paintComponent(Graphics g) { // 必须先调用父类方法,这一步会自动清空面板上的旧绘制内容 super.paintComponent(g); g.setColor(Color.BLACK); // 首次点击前不绘制坐标 if (clickX != -1 && clickY != -1) { g.drawString(clickX + ", " + clickY, clickX, clickY); } } } class GUI { public GUI(){ JFrame displayWindow = new JFrame(); MyPanel myPanel = new MyPanel(); displayWindow.setSize(300,100); displayWindow.setTitle("Title"); // 把自定义面板添加到JFrame内容区域 displayWindow.add(myPanel); // 只给面板加鼠标监听,获取的坐标自动排除标题栏区域 myPanel.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { myPanel.clickX = e.getX(); myPanel.clickY = e.getY(); // 触发面板重绘 myPanel.repaint(); } }); // 用Swing自带的关闭逻辑代替自定义窗口监听器,写法更简洁 displayWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); displayWindow.setVisible(true); } }
关键改动说明
- 删除了自定义继承JFrame的类,不需要修改JFrame本身的逻辑
- 自定义
MyPanel继承JPanel,重写paintComponent()而非paint(),第一行必须调用super.paintComponent(g),该方法会自动用面板背景色清空整个绘制区域,旧文字残影问题会直接解决 - 鼠标监听器只绑定在JPanel上,获取到的坐标天然是面板内的有效坐标,不需要手动减去标题栏高度,正好匹配你最初的需求
- 补上了原代码缺失的main方法,程序可以直接启动运行
通用Swing开发提示:所有自定义绘制逻辑,永远不要直接重写顶层容器(JFrame、JDialog)的paint方法,一律把绘制逻辑放在JPanel等轻量级组件上,重写
paintComponent且第一行调用父类实现,能避开90%的Swing渲染异常问题。
内容的提问来源于stack exchange,提问作者Kevin Adams
相关产品推荐
相关产品推荐

