Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
解决Java Swing绘图应用仅显示最后一个图形的问题:理解引用传递与对象拷贝_创想鸟

解决Java Swing绘图应用仅显示最后一个图形的问题:理解引用传递与对象拷贝

解决java swing绘图应用仅显示最后一个图形的问题:理解引用传递与对象拷贝

本文探讨了Java Swing绘图应用中一个常见问题:程序仅显示最后绘制的图形。核心原因在于Point对象的引用传递机制导致所有图形实例共享并更新相同的坐标数据。解决方案是确保在创建图形对象时,为每个图形实例分配独立的Point对象副本,避免引用共享,同时建议在构造器中进行防御性拷贝以增强代码健壮性。

理解问题:为何只有最后一个图形可见?

在基于Java Swing构建的绘图应用程序中,一个常见的问题是,当用户绘制多个图形(如线条或圆形)时,屏幕上却只显示最后绘制的那个图形。这通常是由于对Java中对象引用传递机制的误解和不当使用造成的。

问题的根源在于,程序中用于记录图形起始点和结束点的Point对象被多个图形实例共享。当用户完成一次绘图操作后,新的图形对象被创建并添加到绘制列表中。然而,如果这些新图形对象接收的是对同一个Point实例的引用,那么当用户再次开始新的绘图操作并更新这些Point实例的坐标时,所有先前创建的图形对象也会“看到”这些更新后的坐标,从而导致它们全部重绘到新的位置,最终只显示最后一个图形。

让我们通过原始代码片段来具体分析这个问题。

原始代码中的问题所在:

立即学习“Java免费学习笔记(深入)”;

在Painter类中,startPoint和endPoint被声明为类的成员变量:

public class Painter implements ActionListener, MouseListener, MouseMotionListener {    // ...    Point startPoint = new Point();    Point endPoint = new Point();    // ...}

在mousePressed和mouseReleased方法中,这两个Point对象的location被更新:

    @Override    public void mousePressed(MouseEvent e) {        startPoint.setLocation(e.getPoint()); // 更新现有startPoint的坐标    }    @Override    public void mouseReleased(MouseEvent e) {        endPoint.setLocation(e.getPoint());   // 更新现有endPoint的坐标        if (object == 0) {            // 将startPoint和endPoint的引用传递给Line构造器            canvas.addPrimitive(new Line(startPoint, endPoint, temp));        }        // ...    }

当Line(或Circle)对象被创建时,它接收的是Painter类成员变量startPoint和endPoint的引用。这意味着,Line对象内部的startPoint和endPoint字段实际上指向了与Painter类中相同的Point对象。因此,每次鼠标释放时,startPoint和endPoint的location被更新,所有之前创建并添加到primitives列表中的Line或Circle对象,由于它们持有相同的Point对象引用,它们的绘制位置也会随之改变,最终所有图形都显示在最后一次绘制的位置上。

解决方案:创建独立的Point对象实例

要解决这个问题,核心在于确保每个绘制的图形对象都拥有自己独立的、不可变的起始点和结束点坐标。这意味着在每次创建新的图形时,都应该创建新的Point对象实例,而不是复用或修改现有的Point对象。

步骤一:在鼠标事件中创建新的Point实例

在Painter类的mousePressed和mouseReleased方法中,不再仅仅更新startPoint和endPoint的坐标,而是直接创建新的Point对象。

修改后的Painter类相关代码:

一览AI绘图 一览AI绘图

一览AI绘图是一览科技推出的AIGC作图工具,用AI灵感助力,轻松创作高品质图片

一览AI绘图 45 查看详情 一览AI绘图

public class Painter implements ActionListener, MouseListener, MouseMotionListener {    // ...    // 可以将startPoint和endPoint初始化为null或在mousePressed中直接赋值    Point startPoint;     Point endPoint;    // ...    @Override    public void mousePressed(MouseEvent e) {        // 直接创建一个新的Point对象,而不是修改现有对象的location        startPoint = new Point(e.getPoint());     }    @Override    public void mouseReleased(MouseEvent e) {        // 同样,创建一个新的Point对象        endPoint = new Point(e.getPoint());         if (object == 0) {            // 现在传递的是新创建的、独立的Point对象引用            canvas.addPrimitive(new Line(startPoint, endPoint, temp));                  }        if (object == 1){            canvas.addPrimitive(new Circle(startPoint, endPoint, temp));                    }        canvas.repaint();    }    // ...}

通过startPoint = new Point(e.getPoint());和endPoint = new Point(e.getPoint());,我们确保了每次鼠标按下和释放时,都会创建全新的Point对象,这些对象包含了当前鼠标事件的准确坐标。当这些新的Point对象被传递给Line或Circle的构造器时,每个图形实例都将持有其独特的坐标信息,不再受后续绘图操作的影响。

步骤二(推荐):防御性拷贝以增强健壮性

尽管步骤一已经解决了核心问题,但为了代码的健壮性和防止未来可能出现的意外行为(例如,如果Point对象在其他地方被意外修改),最佳实践是在图形(如Line或Circle)的构造器中也进行一次“防御性拷贝”。这意味着即使传入的Point对象在外部被修改,图形实例内部的坐标也不会受到影响。

修改后的Line类构造器:

import java.awt.Graphics;import java.awt.Point;import java.awt.Color;public class Line extends PaintingPrimitive{    Point startPoint; // 无需初始化,将在构造器中赋值    Point endPoint;   // 无需初始化,将在构造器中赋值    public Line(Point start, Point end, Color c) {        super(c);        // 对传入的Point对象进行防御性拷贝,确保Line实例持有独立的Point对象        this.startPoint = new Point(start);         this.endPoint = new Point(end);    }    public void drawGeometry(Graphics g) {        System.out.println("draw geo called"); // 注意:在实际应用中应避免在paintComponent中进行System.out.println,会影响性能        g.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);    }    @Override    public String toString() {        return "Line";    }}

通过在Line构造器中使用new Point(start)和new Point(end),即使Painter类中startPoint和endPoint成员变量的引用在未来被不当地复用或修改,已经创建的Line对象也不会受到影响,因为它拥有自己独立的坐标副本。

完整的PaintingPanel类(修正示例代码中的冗余绘制)

PaintingPanel类中的paintComponent方法负责实际的绘制工作。原始代码中包含了一行g.drawLine(0,0,100,100);,这行代码会在每次重绘时额外绘制一条从(0,0)到(100,100)的固定线条。这通常不是期望的行为,应将其移除。

修正后的PaintingPanel类:

import java.util.ArrayList;import javax.swing.JPanel;import java.awt.Graphics;import java.awt.Color;public class PaintingPanel extends JPanel {    ArrayList primitives = new ArrayList();    PaintingPanel() {        setBackground(Color.WHITE);    }    public void addPrimitive(PaintingPrimitive obj) {        primitives.add(obj);        this.repaint(); // 添加新图形后立即请求重绘    }    @Override    protected void paintComponent(Graphics g) {        super.paintComponent(g); // 必须调用父类的paintComponent来清空背景等        // 遍历并绘制所有存储的图形基元        for (PaintingPrimitive shape : primitives) {            // 移除不必要的固定线条绘制            // g.drawLine(0,0,100,100);             shape.draw(g);        }    }}

总结与注意事项

通过以上修改,你的Java Swing绘图应用程序将能够正确地显示所有绘制的图形,而不仅仅是最后一个。

核心要点回顾:

理解引用传递: 在Java中,对象变量存储的是对象的引用。当一个对象作为参数传递或赋值给另一个变量时,传递的是引用本身,而不是对象的副本。创建独立实例: 当你需要每个逻辑实体(如本例中的每个Line或Circle)拥有其独立的数据状态时,务必创建新的对象实例,而不是复用或修改共享的实例。防御性拷贝: 在对象的构造器中对传入的可变对象参数进行拷贝,是一种良好的编程习惯,可以有效防止外部修改对内部状态造成意外影响,提高代码的健壮性。paintComponent的正确使用: paintComponent方法应该只包含绘制逻辑,避免执行耗时操作(如System.out.println)或修改应用程序状态。始终先调用super.paintComponent(g)。

遵循这些原则,你将能更好地管理Java Swing应用程序中的对象状态,创建出功能更稳定、行为更符合预期的图形界面。

以上就是解决Java Swing绘图应用仅显示最后一个图形的问题:理解引用传递与对象拷贝的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/324136.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
如何用VSCode设置PHP注释模板 VSCode快速插入PHP注释技巧
上一篇 2025年11月5日 11:18:23
详解thinkphp中视图和模板的区别
下一篇 2025年11月5日 11:18:32

相关推荐

  • 新安装win10怎么登录老账户的详细介绍

    新安装win10怎么登录老账户的详细介绍新安装win10怎么登录老账户的详细介绍新安装win10怎么登录老账户的详细介绍新安装win10怎么登录老账户的详细介绍

    在windows 10系统里,能够通过微软账户登录,但不少用户在重装系统后进入设置界面时,往往不清楚如何使用之前的微软账户来继续操作。那么,新安装的系统如何使用旧账户呢?下面,我们将为大家介绍具体的操作步骤。 如何在新装的Windows 10系统中登录旧账户 点击桌面左下角的开始按钮。 进入设置页面…

    2026年9月28日 • 用户投稿
    1000
  • 深入理解Java泛型:类型参数与方法重载的实践指南

    深入理解Java泛型:类型参数与方法重载的实践指南深入理解Java泛型:类型参数与方法重载的实践指南深入理解Java泛型:类型参数与方法重载的实践指南深入理解Java泛型:类型参数与方法重载的实践指南

    本文深入探讨了Java泛型中关于类型参数与泛型类实例在方法签名中的区别,以及由此引发的类型不匹配问题。通过一个具体的代码示例,详细解析了为何在泛型方法中,直接传入泛型类实例或其内部类型参数会引发编译错误,并提供了利用方法重载这一核心机制来优雅地解决此类问题的专业指导和示例代码,帮助开发者清晰理解“h…

    2026年9月28日 • 用户投稿
    100
  • 抖音私信怎么屏蔽?抖音私信怎么屏蔽一个人的消息

    抖音私信怎么屏蔽?抖音私信怎么屏蔽一个人的消息抖音私信怎么屏蔽?抖音私信怎么屏蔽一个人的消息抖音私信怎么屏蔽?抖音私信怎么屏蔽一个人的消息抖音私信怎么屏蔽?抖音私信怎么屏蔽一个人的消息

    随着抖音的普及,越来越多用户加入这个短视频社交平台。在日常使用中,不少人会收到陌生或不想要的私信,甚至遭遇骚扰信息。为了更好地保护个人隐私和使用体验,掌握屏蔽私信的方法显得尤为重要。接下来,就为大家详细介绍如何有效屏蔽抖音私信。 一、屏蔽抖音私信的具体操作 1. 屏蔽某个特定用户 当你希望阻止某位用…

    2026年9月28日 • 用户投稿
    000
  • sublime怎么多行编辑_Sublime多光标与多行编辑技巧详解

    sublime怎么多行编辑_Sublime多光标与多行编辑技巧详解sublime怎么多行编辑_Sublime多光标与多行编辑技巧详解sublime怎么多行编辑_Sublime多光标与多行编辑技巧详解sublime怎么多行编辑_Sublime多光标与多行编辑技巧详解

    掌握Sublime Text多光标与列编辑技巧可大幅提升效率:1. 按Ctrl/Cmd点击或Ctrl+Alt+方向键添加多光标;2. 用Ctrl+D选相同词,Ctrl+Shift+L拆分多行;3. Shift+Alt拖动实现列选择;4. 应用于批量加符号、生成代码、对齐数据等场景。 Sublime …

    2026年9月28日 • 用户投稿
    100
  • 如何用豆包AI写协程代码 协程代码的AI编写技巧大公开

    如何用豆包AI写协程代码 协程代码的AI编写技巧大公开如何用豆包AI写协程代码 协程代码的AI编写技巧大公开如何用豆包AI写协程代码 协程代码的AI编写技巧大公开如何用豆包AI写协程代码 协程代码的AI编写技巧大公开

    用豆包ai写协程代码的关键在于提问方式与后续优化。一、明确所需协程类型,如并发下载或任务管理,提问越具体生成代码越实用;二、注意避免阻塞调用,如将time.sleep改为await asyncio.sleep;三、善用提示词提升代码质量,如指定库、并发数及异常处理;四、结合项目结构调整代码,适配模块…

    2026年9月28日 • 用户投稿
    200
  • Win10计算器应用现在支持图形模式下的深色主题

    Win10计算器应用现在支持图形模式下的深色主题Win10计算器应用现在支持图形模式下的深色主题Win10计算器应用现在支持图形模式下的深色主题Win10计算器应用现在支持图形模式下的深色主题

    去年3月,微软宣布正在为Windows Calculator应用开发全新的图形化功能。今年,微软已开始在Windows 10及Windows 10 S设备上逐步推出这一图形模式功能。近期,微软通过更新Windows 10计算器至10.2005.23.0版本,进一步增强了图形模式,新增了深色主题的支持…

    2026年9月28日 • 用户投稿
    000
  • 洗碗机普及迎来攻坚战,行业探寻市场爆发“黄金拐点”

    洗碗机普及迎来攻坚战,行业探寻市场爆发“黄金拐点”洗碗机普及迎来攻坚战,行业探寻市场爆发“黄金拐点”洗碗机普及迎来攻坚战,行业探寻市场爆发“黄金拐点”洗碗机普及迎来攻坚战,行业探寻市场爆发“黄金拐点”

    家电行业中,谁是最被看好的“潜力股”之一?洗碗机当之不让。但是现实困境却是,洗碗机渗透率徘徊在4%左右迟迟难以突破,原因何在,又该如何破局? 2025年9月17日,由中国家电网主办的“碗美无菌国补焕新2025中国洗碗机行业高峰论坛”在千年瓷都景德镇拉开帷幕,来自A.O.史密斯、卡萨帝、finish亮…

    2026年9月28日 • 用户投稿
    100
  • 如何用豆包AI生成Python环境配置代码

    如何用豆包AI生成Python环境配置代码如何用豆包AI生成Python环境配置代码如何用豆包AI生成Python环境配置代码如何用豆包AI生成Python环境配置代码

    豆包ai可辅助生成python环境配置代码。1. 首先明确项目需求,如python版本、依赖库和虚拟环境类型;2. 向豆包ai输入具体提示词,获取创建venv和requirements.txt的命令;3. 如需复杂配置,可要求生成开发与生产环境分离的依赖文件;4. 注意版本控制、输出验证及通过多轮交…

    2026年9月28日 • 用户投稿
    100
  • windows8桌面右键新建菜单很卡怎么办_windows8右键菜单卡顿修复方法

    右键菜单卡顿因注册表冗余或软件冲突,需清理ContextMenuHandlers项、删除非New子项、用搜索功能查Directory路径并删多余项,卸载360或NVIDIA等第三方软件,更新显卡蓝牙驱动解决。 如果您在Windows 8桌面上右键点击时,新建菜单响应缓慢或出现卡顿现象,这通常与系统右…

    2026年9月28日
    200
  • 【Linux笔记】系统目录结构

    【Linux笔记】系统目录结构【Linux笔记】系统目录结构【Linux笔记】系统目录结构【Linux笔记】系统目录结构

    前言 在Linux或Unix操作系统中,所有的文件和目录都是以一个根节点开始的倒置树状结构组织起来的。文件系统的最高层是根目录,用/表示。根目录下可以包含目录和文件,每个目录又可以包含子目录和文件,这样反复构建起一个庞大的文件系统。 在超级用户模式下,在根目录/下执行ls命令,输出如下(本文演示的L…

    2026年9月28日 • 用户投稿
    200
  • JPype集成Aspose.Cells:解决Java堆内存溢出错误指南

    JPype集成Aspose.Cells:解决Java堆内存溢出错误指南JPype集成Aspose.Cells:解决Java堆内存溢出错误指南JPype集成Aspose.Cells:解决Java堆内存溢出错误指南JPype集成Aspose.Cells:解决Java堆内存溢出错误指南

    当Python程序通过JPype调用Java库(如Aspose.Cells)处理大型文件时,可能遭遇java.lang.OutOfMemoryError: Java heap space。本文将详细指导如何通过在jpype.startJVM()中配置JVM的最大堆内存参数来有效解决此类问题,确保Py…

    2026年9月28日 • 用户投稿
    200
  • sublime怎么快速注释和取消注释代码_Sublime代码块注释与取消注释的快捷操作

    sublime怎么快速注释和取消注释代码_Sublime代码块注释与取消注释的快捷操作sublime怎么快速注释和取消注释代码_Sublime代码块注释与取消注释的快捷操作sublime怎么快速注释和取消注释代码_Sublime代码块注释与取消注释的快捷操作sublime怎么快速注释和取消注释代码_Sublime代码块注释与取消注释的快捷操作

    Sublime Text中行注释快捷键为Ctrl + /(Windows/Linux)或Cmd + /(macOS),用于单行或多行代码的快速注释与取消;块注释快捷键为Ctrl + Shift + / 或Cmd + Shift + /,可将选中代码块用语言特定符号包裹。 在Sublime Text中…

    2026年9月28日 • 用户投稿
    100
  • 豆包AI生成项目预算表的技巧 快速规划资源投入的指南

    豆包AI生成项目预算表的技巧 快速规划资源投入的指南豆包AI生成项目预算表的技巧 快速规划资源投入的指南豆包AI生成项目预算表的技巧 快速规划资源投入的指南豆包AI生成项目预算表的技巧 快速规划资源投入的指南

    做项目预算的关键是明确目标与合理分类。首先需明确项目目标和范围,向豆包ai输入一句话生成初步预算框架;其次将预算分为人力、技术、外包等清晰类别,并用工具生成参考表格;三要为每项预算预留弹性空间,尤其ai项目的不确定性环节;四要定期更新对比预算,利用豆包ai的协作功能跟踪变化并分析调整。 ☞☞☞AI …

    2026年9月28日 • 用户投稿
    100
  • 如何通过服务禁用减少系统启动时间?

    如何通过服务禁用减少系统启动时间?如何通过服务禁用减少系统启动时间?如何通过服务禁用减少系统启动时间?如何通过服务禁用减少系统启动时间?

    精简开机自启动服务可显著缩短系统启动时间。通过禁用非必要的第三方或冗余服务,减轻系统引导负担,释放CPU、内存等资源,提升整体响应速度与电池续航。在Windows中使用services.msc或任务管理器管理服务与启动项,Linux下则用systemctl命令控制服务启停。操作时应从第三方软件入手,…

    2026年9月28日 • 用户投稿
    300
  • 抖音直播怎么卖自己的货?抖音怎么直播挣钱

    抖音直播怎么卖自己的货?抖音怎么直播挣钱抖音直播怎么卖自己的货?抖音怎么直播挣钱抖音直播怎么卖自己的货?抖音怎么直播挣钱抖音直播怎么卖自己的货?抖音怎么直播挣钱

    在当今这个互联网时代,短视频平台已经成为人们日常生活中不可或缺的一部分。抖音作为国内领先的短视频平台,其强大的流量和用户基础,使得越来越多的商家和创业者纷纷加入抖音直播带货的行列。抖音直播究竟该如何卖出自己的货呢?下面,就让我来为大家详细讲解一下。 一、选品定位 在抖音直播带货之前,首先要明确自己的…

    2026年9月28日 • 用户投稿
    000
  • 十一小长假肆意畅玩!华硕RTX5060甜品卡全力助能

    十一小长假肆意畅玩!华硕RTX5060甜品卡全力助能十一小长假肆意畅玩!华硕RTX5060甜品卡全力助能十一小长假肆意畅玩!华硕RTX5060甜品卡全力助能十一小长假肆意畅玩!华硕RTX5060甜品卡全力助能

    十一假期的脚步渐近,想想即将到来的悠闲小长假,小伙伴们准备怎样度过呢?宅家开启电竞狂欢才是明智之选!在这个假期,有诸多佳作等你来战,准备好投身一场热血沸腾的电竞之旅了吗~ 想要顺利畅享游戏大作带来的极致体验,DLSS技术的支持至关重要。DLSS是一套创新性的神经网络渲染技术,借助AI提升帧率、降低延…

    2026年9月28日 • 用户投稿
    400
  • 使用 Java 泛型实现 CSV 到对象的转换器

    使用 Java 泛型实现 CSV 到对象的转换器使用 Java 泛型实现 CSV 到对象的转换器使用 Java 泛型实现 CSV 到对象的转换器使用 Java 泛型实现 CSV 到对象的转换器

    本文将介绍如何使用 Java 泛型创建一个通用的 CSV 到对象的转换器。通过泛型,我们可以避免为每种需要转换的 Java 类编写重复的代码,从而提高代码的可重用性和可维护性。文章将提供代码示例,并讨论一些关于代码设计和现有 CSV 解析库的建议。 泛型 CSV 工具类 使用 Java 泛型可以创建…

    2026年9月28日 • 用户投稿
    100
  • sublime怎么显示函数列表_Sublime Text快速跳转到函数或符号定义

    sublime怎么显示函数列表_Sublime Text快速跳转到函数或符号定义sublime怎么显示函数列表_Sublime Text快速跳转到函数或符号定义sublime怎么显示函数列表_Sublime Text快速跳转到函数或符号定义sublime怎么显示函数列表_Sublime Text快速跳转到函数或符号定义

    使用Ctrl+R或Cmd+R调用内置符号跳转功能,可快速定位当前文件的函数、类等定义;通过安装CTags、Symbol Browser或SublimeCodeIntel等插件,能实现跨文件跳转与更精准识别;配合LSP插件启用Goto Definition(F12),可获得类似IDE的智能跳转体验,显…

    2026年9月28日 • 用户投稿
    400
  • 电脑安全模式的作用

    电脑安全模式的作用电脑安全模式的作用电脑安全模式的作用电脑安全模式的作用

    电脑安全模式的功能解析: 清除顽固文件 在Windows系统中,当我们尝试删除某些文件或清空回收站时,可能会遇到提示「某文件正在使用中,无法删除」的情况。尽管文件实际上并未被使用,此时可尝试重启电脑,并在启动时进入安全模式。进入安全模式后,Windows会自动释放这些文件的控制权,从而顺利将其删除。…

    2026年9月28日 • 用户投稿
    200
  • ROG Xbox Ally和ROG Xbox Ally X将于10月16日发售

    ROG Xbox Ally和ROG Xbox Ally X将于10月16日发售ROG Xbox Ally和ROG Xbox Ally X将于10月16日发售ROG Xbox Ally和ROG Xbox Ally X将于10月16日发售ROG Xbox Ally和ROG Xbox Ally X将于10月16日发售

    微软与华硕联手打造的windows掌机rog xbox ally及高端型号rog xbox ally x确认将于2025年10月16日正式发售,为全球玩家带来全新的掌上游戏体验。据悉,该系列掌机将在8月20日科隆游戏展期间开启预售,届时玩家也有机会在现场近距离体验这款设备。 此次发布的ROG Xbo…

    2026年9月28日 • 用户投稿
    100

发表回复

登录后才能评论
关注微信