0

0

使用 Swing 实现跟随鼠标的动态笑脸绘制

DDD

DDD

发布时间:2025-10-02 15:30:00

|

325人浏览过

|

来源于php中文网

原创

使用 Swing 实现跟随鼠标的动态笑脸绘制

本教程将指导您如何使用 Java Swing 和 AWT 实现一个能够跟随鼠标移动的动态笑脸。我们将详细讲解 MouseMotionListener 接口的应用,并修正 paintComponent 方法中的坐标逻辑,确保笑脸的绘制位置能实时响应鼠标事件,从而创建出交互式的图形用户界面。

1. 问题分析:为什么笑脸没有移动?

在 swing 中,自定义图形的绘制主要通过重写 jpanel 的 paintcomponent(graphics g) 方法来完成。当需要图形响应用户交互(如鼠标移动)时,我们通常会:

  1. 实现相应的事件监听器(例如 MouseMotionListener)。
  2. 在事件处理方法中(如 mouseMoved 或 mouseDragged)更新图形的位置变量。
  3. 调用 repaint() 方法请求 Swing 重新绘制组件。

然而,一个常见的错误是,即使在事件处理方法中更新了位置变量,但在 paintComponent 方法中,图形的绘制坐标仍然是硬编码的固定值,而不是基于这些更新后的变量。这就导致了图形始终停留在初始位置,无法跟随鼠标移动。

2. 解决方案:动态坐标绘制

要解决此问题,核心在于将图形的绘制逻辑与鼠标事件更新的坐标变量紧密关联。具体步骤如下:

  1. 定义实例变量: 在 JPanel 子类中定义 x 和 y 等实例变量,用于存储图形的当前位置(例如,笑脸的左上角或中心点坐标)。
  2. 初始化位置: 为 x 和 y 设置一个初始值,作为笑脸的默认显示位置。
  3. 更新坐标: 在 MouseMotionListener 的 mouseMoved 和 mouseDragged 方法中,获取鼠标的当前坐标,并将其赋值给 x 和 y。为了使笑脸的中心与鼠标位置对齐,可能需要根据笑脸的大小对鼠标坐标进行适当的偏移调整。
  4. 触发重绘 在更新 x 和 y 后,调用 repaint() 方法。这将通知 Swing 组件需要重新绘制,从而触发 paintComponent 方法的执行。
  5. 相对绘制: 在 paintComponent 方法中,所有笑脸组成部分(脸部轮廓、眼睛、嘴巴等)的绘制坐标都必须基于 x 和 y 进行相对计算,而不是使用固定值。

3. 示例代码:实现跟随鼠标的笑脸

下面是修正后的 SmileyFace 类代码,它演示了如何正确实现一个跟随鼠标移动的动态笑脸:

Manus
Manus

全球首款通用型AI Agent,可以将你的想法转化为行动。

下载
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SmileyFace extends JPanel implements MouseMotionListener {
    private int x = 100; // 笑脸的初始X坐标(左上角)
    private int y = 100; // 笑脸的初始Y坐标(左上角)
    private static final int SMILEY_DIAMETER = 200; // 笑脸的直径
    private static final int SMILEY_RADIUS = SMILEY_DIAMETER / 2; // 笑脸的半径

    public SmileyFace() {
        // 设置面板的首选大小,确保有足够的空间显示笑脸
        setPreferredSize(new Dimension(400, 400));
        // 将MouseMotionListener添加到面板自身
        addMouseMotionListener(this);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); // 调用父类的paintComponent,清除背景

        // 绘制笑脸
        // 1. 绘制脸部背景(黄色圆)
        g.setColor(Color.YELLOW);
        g.fillOval(x, y, SMILEY_DIAMETER, SMILEY_DIAMETER);

        // 2. 绘制脸部轮廓(黑色圆)
        g.setColor(Color.BLACK);
        g.drawOval(x, y, SMILEY_DIAMETER, SMILEY_DIAMETER);

        // 3. 绘制眼睛(两个小黑点)
        // 左眼:相对于笑脸左上角 (x, y) 进行偏移
        g.fillOval(x + SMILEY_DIAMETER / 4, y + SMILEY_DIAMETER / 4, SMILEY_DIAMETER / 10, SMILEY_DIAMETER / 10);
        // 右眼:相对于笑脸左上角 (x, y) 进行偏移
        g.fillOval(x + SMILEY_DIAMETER * 3 / 4 - SMILEY_DIAMETER / 10, y + SMILEY_DIAMETER / 4, SMILEY_DIAMETER / 10, SMILEY_DIAMETER / 10);

        // 4. 绘制嘴巴(弧形)
        // 嘴巴的外接矩形左上角坐标,相对于笑脸左上角 (x, y) 偏移
        g.drawArc(x + SMILEY_DIAMETER / 4, y + SMILEY_DIAMETER * 2 / 3,
                  SMILEY_DIAMETER / 2, SMILEY_DIAMETER / 5, 0, -180); // 从0度到-180度绘制一个下弧
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        // 当鼠标拖动时,更新笑脸的坐标
        // 调整 x, y 使鼠标指针位于笑脸的中心
        x = e.getX() - SMILEY_RADIUS;
        y = e.getY() - SMILEY_RADIUS;
        repaint(); // 请求重绘组件
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        // 当鼠标移动时,更新笑脸的坐标
        // 调整 x, y 使鼠标指针位于笑脸的中心
        x = e.getX() - SMILEY_RADIUS;
        y = e.getY() - SMILEY_RADIUS;
        repaint(); // 请求重绘组件
    }

    public static void main(String[] args) {
        // 在主方法中创建并显示窗口
        JFrame frame = new JFrame("跟随鼠标的动态笑脸");
        SmileyFace smileyPanel = new SmileyFace();
        frame.add(smileyPanel); // 将笑脸面板添加到窗口
        frame.pack(); // 根据组件的首选大小调整窗口大小
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置关闭操作
        frame.setLocationRelativeTo(null); // 窗口居中显示
        frame.setVisible(true); // 使窗口可见
    }
}

4. 代码详解与注意事项

  • SmileyFace 类结构:
    • 继承 JPanel 以便进行自定义绘制。
    • 实现 MouseMotionListener 接口以监听鼠标移动和拖动事件。
    • x, y: private 实例变量,存储笑脸左上角的当前坐标。它们是笑脸所有绘制操作的基准。
    • SMILEY_DIAMETER, SMILEY_RADIUS: 常量,用于定义笑脸的大小,并方便计算内部组件的相对位置,提高了代码的可读性和可维护性。
  • 构造函数 SmileyFace():
    • setPreferredSize(new Dimension(400, 400)): 为面板设置一个推荐大小,确保笑脸有足够的空间显示和移动。在 main 方法中调用 frame.pack() 时,窗口会根据这个大小进行调整。
    • addMouseMotionListener(this): 将当前 SmileyFace 实例注册为自身的鼠标移动监听器。
  • paintComponent(Graphics g) 方法:
    • super.paintComponent(g): 非常重要! 必须首先调用父类的 paintComponent 方法,以确保组件的背景被正确清除,避免出现残影。
    • 所有的 fillOval 和 drawOval 等绘制方法的坐标都基于 x 和 y 进行计算。例如,笑脸主体圆的左上角就是 (x, y)。眼睛和嘴巴的坐标通过在 x 和 y 上加上相应的偏移量来定位,确保它们始终在笑脸内部的正确位置。
  • mouseDragged(MouseEvent e) 和 mouseMoved(MouseEvent e) 方法:
    • 这两个方法会在鼠标移动或拖动时被调用。
    • e.getX() 和 e.getY() 获取鼠标指针在组件内的当前坐标。
    • x = e.getX() - SMILEY_RADIUS; 和 y = e.getY() - SMILEY_RADIUS;: 这里进行了一个关键的调整。如果直接将 e.getX() 和 e.getY() 赋值给 x 和 y,那么笑脸的左上角会跟随鼠标指针。为了让鼠标指针位于笑脸的中心,我们需要从鼠标坐标中减去笑脸的半径 (SMILEY_RADIUS),这样 (x, y) 就成为了笑脸左上角的新坐标。
    • repaint(): 至关重要! 每当 x 或 y 改变时,必须调用 repaint() 来通知 Swing 重新绘制组件。这会间接触发 paintComponent 方法的执行,从而在新的位置绘制笑脸。
  • main 方法:
    • 标准的 Swing 应用程序启动代码,创建 JFrame 窗口,将 SmileyFace 面板添加到窗口中,并设置窗口的关闭行为、大小和可见性。
    • frame.pack(): 建议使用,它会根据 smileyPanel 的 setPreferredSize 自动调整 JFrame 的大小。

5. 总结

通过本教程,我们深入理解了在 Java Swing 中实现动态图形绘制的关键机制。核心在于:

  1. 使用实例变量存储图形的动态位置。
  2. 通过事件监听器(如 MouseMotionListener)实时更新这些位置变量。
  3. 在 paintComponent 方法中,所有绘制操作都基于这些动态变量进行相对定位。
  4. 每次位置更新后,调用 repaint() 强制组件重绘。

掌握这些原则,您将能够创建各种响应用户交互的动态和交互式 Swing 图形界面应用。

相关文章

Windows激活工具
Windows激活工具

Windows激活工具是正版认证的激活工具,永久激活,一键解决windows许可证即将过期。可激活win7系统、win8.1系统、win10系统、win11系统。下载后先看完视频激活教程,再进行操作,100%激活成功。

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1502

2023.10.24

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1502

2023.10.24

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1502

2023.10.24

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1133

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

213

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1805

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

20

2026.01.19

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

1

2026.01.29

java配置环境变量教程合集
java配置环境变量教程合集

本专题整合了java配置环境变量设置、步骤、安装jdk、避免冲突等等相关内容,阅读专题下面的文章了解更多详细操作。

2

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3万人学习

C# 教程
C# 教程

共94课时 | 7.9万人学习

Java 教程
Java 教程

共578课时 | 53.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号