swing快速入门(二十四)绘画板-可调色

注释很详细,直接上代码

上一篇

Look here~
听我说完再继续看更容易理解:
如果说用之前的绘图方法写一个绘画板你会怎么做?重绘会让之前的内容消失呀,用各种数据结构记录每个像素点的位置或颜色?嘶,感觉很麻烦对吧。位图便解决了这个问题,相当于给你一个图层进行绘画,画完每一步都会实时显示在绘画区域,这样就实现了像素点的记录。下面来实践一下~

新增内容

1. 使用位图记录绘画痕迹

2. 继承Canvas类,重写paint方法显示位图

3.鼠标移动响记录上次与当此位置进行连线化曲为直

4.处理鼠标左键刚按下时没有上一次坐标的情况

5.特判鼠标右键的菜单响应情况

package swing21_30;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;

public class swing_test_22 {

    private Frame frame =new Frame("手绘程序");

    //定义画图区的宽高
    private static final int WIDTH = 600;
    private static final int HEIGHT = 600;

    //记录鼠标上一次拖动过程中的位置
    private int prex=-1;
    private int prey=-1;

    //定义一个右键菜单,用于设置画笔的颜色
    private PopupMenu colorMenu=new PopupMenu("");
    private MenuItem redItem=new MenuItem("红色");
    private MenuItem greenItem=new MenuItem("绿色");
    private MenuItem blueItem=new MenuItem("蓝色");

    //定义一个变量记录当前画笔颜色
    private Color forceColor=Color.BLACK;

    //创建一个BufferImage对象,用于绘制图形
    private BufferedImage image=new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB);//TYPE_INT_RGB表示使用RGB颜色模型

    //通过位图,获取关联的Graphics对象
    Graphics g=image.getGraphics();

    //自定义一个类,继承Canvas类,重写paint方法
    class MyCanvas extends Canvas{
        @Override

        public void paint(Graphics g){
            g.drawImage(image,0,0,null);//绘制图片
        }
    }

    //创建一个画图区
    MyCanvas drawArea=new MyCanvas();



    public void init(){

        //组装视图

        //创建监听器
        ActionListener listener=new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //获取控件文本
                String actionCommand=e.getActionCommand();
                switch (actionCommand){
                    case "红色":
                        forceColor=Color.RED;
                        break;
                    case "绿色":
                        forceColor=Color.GREEN;
                        break;
                    case "蓝色":
                        forceColor=Color.BLUE;
                        break;
                }
            }
        };

        //注册监听器
        redItem.addActionListener(listener);
        greenItem.addActionListener(listener);
        blueItem.addActionListener(listener);

        //组装菜单
        colorMenu.add(redItem);
        colorMenu.add(greenItem);
        colorMenu.add(blueItem);

        //将菜单设置给绘图区域
        drawArea.add(colorMenu);

        //鼠标抬起响应
        drawArea.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                //特判触发右键菜单的情况
               boolean popupTriggered=e.isPopupTrigger();
               if(popupTriggered){
                   //显示右键菜单
                   colorMenu.show(drawArea,e.getX(),e.getY());
               }

               //重置prex和prey的值
               prex=-1;
               prey=-1;
            }
        });

        //设置背景为白色
        g.setColor(Color.WHITE);
        g.fillRect(0,0,WIDTH,HEIGHT);

        //通过鼠标移动监听器
        drawArea.addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                //获取当前鼠标位置
                int x=e.getX();
                int y=e.getY();
                if(prex!=-1&&prey!=-1){
                    g.setColor(forceColor);

                    //根据鼠标拖动的距离,绘制线条
                    g.setColor(forceColor);
                    g.drawLine(prex,prey,x,y);
                };

                //修正prex和prey的值
                prex=e.getX();
                prey=e.getY();

                //因为在位图上完成了但是还未显示在绘图区,这里需要刷新一下绘图区
                //刷新绘图区
                drawArea.repaint();
            }
        });

        //设置最佳大小
        drawArea.setPreferredSize(new Dimension(WIDTH,HEIGHT));

        frame.add(drawArea);

        //设置最佳大小且可见
        frame.pack();
        frame.setVisible(true);

    }

    public static void main(String[] args) {
        new swing_test_22().init();
    }
}

演示效果:

右键显示颜色选项

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/266245.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】递归与分治

一.递归 1.递归的概念: 子程序(或函数). 接调用自己或通过一系列调用语句间接调用自己,成为递归。 递归是一种描述问题和解决问题的基本方法。 重复地把问题转化为与原问题相似的新问题,直到问题解决为止。 2.递归…

MyBatis 架构分析

文章目录 三层架构一、基础支撑层1.1 类型转换模块1.2 日志模块1.3 反射工具模块1.4 Binding 模块1.5 数据源模块1.6 缓存模块1.6 解析器模块1.7 事务管理模块 二、核心处理层2.1 配置解析2.2 SQL 解析与 scripting 模块。2.3 MyBatis 中的 scripting 模块就是负责动态生成 SQL…

111基于matlab的粒子滤波进行锂离子电池的循环寿命预测

基于matlab的粒子滤波进行锂离子电池的循环寿命预测,输出实验、粒子滤波及自然预测数据结果。程序已调通,可直接运行。 111matlab锂离子电池寿命预测 (xiaohongshu.com)

Git安装和使用教程,并以gitee为例实现远程连接远程仓库

文章目录 1、Git简介及安装2、使用方法2.1、Git的启动与配置2.2、基本操作2.2.1、搭建自己的workspace2.2.2、git add2.2.3、git commit2.2.4、忽略某些文件不予提交2.2.5、以gitee为例实现git连接gitee远程仓库来托管代码 1、Git简介及安装 版本控制(Revision cont…

C/C++ 连接访问 MySQL数据库

前面我们已经讲述了MySQL的基础使用,现在我们来看一下如何使用语言来操作数据库。在实际开发中,语言连接MySQL是为了能够在编程语言中与MySQL数据库进行交互和操作。大部分情况我们都是通过语言连接MySQL,建立与MySQL数据库的连接&#xff0c…

springboot实现发送邮件开箱即用

springboot实现发送邮件开箱即用 环境依赖包yml配置Service层Controller层测试 环境 jdk17 springboot版本3.2.1 依赖包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId><ver…

分布式系统架构设计之分布式数据管理

随着互联网时代的不断发展&#xff0c;分布式系统架构成为支撑大规模用户和高并发访问的基础。在构建分布式系统时&#xff0c;分布式系统有着一系列的要求以及对应的核心技术&#xff0c;涉及到数据管理、通信安全性、性能优化、可扩展性设计以及架构演进与版本管理等很多方面…

N字形变换(麻烦的方法)

class Solution:def convert(self, s: str, numRows: int) -> str:#先判断z有多少隔开s_new""index_now0if len(s)<numRows or numRows1:return sfor i in range(numRows-1,-1,-1):exchange0index_exchangeindex_nows_news[index_now]#计算每一层的差距gap_but…

【零基础入门Python】Python参数

✍面向读者&#xff1a;所有人 ✍所属专栏&#xff1a;零基础入门Pythonhttps://blog.csdn.net/arthas777/category_12455877.html 目录 print&#xff08;&#xff09;中的Python结束参数 print&#xff08;&#xff09;中的Python|sep参数 Python的格式转换规则 使用格式…

Vue如何请求接口——axios请求

1、安装axios 在cmd或powershell打开文件后&#xff0c;输入下面的命令 npm install axios 可在项目框架中的package.json中查看是否&#xff1a; 二、引用axios import axios from axios 在需要使用的页面中引用 三、get方式使用 get请求使用params传参,本文只列举常用参数…

java中线程相关的面试题

什么是线程安全&#xff0c;造成线程安全的本质是什么&#xff1f; 什么是线程安全呢&#xff1f; 咱们初步去理解话记住一句话就行&#xff1a;如果一个对象可以安全地被多个线程同时使用&#xff0c;那它就是线程安全的。 为什么并发编程会导致线程不安全&#xff1f; 可见…

用户认证篇

文章目录 1. 如何生成用户认证token令牌1.1 相关表1.2 生成令牌逻辑1.3 最终结果 2. 如何认证用户token令牌2.1 前端组件2.2 TokenAuthenticationFilter2.3 获得登陆用户 3. 如何刷新用户认证 Token 令牌3.1 前端组件3.2 刷新令牌接口 4. 如何模拟用户认证token令牌5. 如何实现…

php学习03-php注释

<?php //单行注释 echo ;//单行注释//单行注释嵌套 /*** 多行注释* 多行注释不允许嵌套*/ $c 12; # 这也是单行注释 #嵌套 /*** 文档注释*/ class Util{/*** 方法注释* param int $num* return int*/function add($num){return 11$num;} }echo 这样会出错的//不会看打到?…

linux的主线程提前子线程退出以及线程分离

主线程提前退出 如果主线程没有等待子线程提前退出&#xff0c;可能会发生以下情况&#xff1a; 子线程继续运行&#xff1a;如果主线程退出&#xff0c;但子线程仍在执行任务&#xff0c;子线程将继续独立运行。子线程的生命周期不受主线程控制&#xff0c;直到子线程自行完成…

基于Springboot的留守儿童爱心网站(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的留守儿童爱心网站(有报告)。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring…

蓝牙物联网在智能家居中的应用前景

物联网智能家居系统是应用物联网技术&#xff0c;在传统家居环境下将各种零散无序的电器整合成统一整体&#xff0c;实现家电的全程自动控制&#xff0c;满足用户高效管理需求的一种新型家居模式。 其主要的子系统有家居感知系统、家庭网络系统、智能家居控制管理系统等&#x…

LINUX 嵌入式应用开发层细节知识(入职体验)

1. 后台进程 一些辅助监测的工作&#xff08;日志系统&#xff0c;OTA升级&#xff0c;云-本地中转) 进程可以设置为守护进程 nohup nohub、&、setsid nohup 是可以忽略所有信号&#xff0c;让程序进入后台进程模式。‘ 2. IPCS -ipc_index 查询IPC目前的使用情况 3.…

微信小程序开发学习(上强度):从0开始写项目

前置知识 1、配置插件 微信小程序 基础模板引入sass的两种方法_微信小程序使用sass-CSDN博客 之后在对应页面里新建一个scss文件&#xff0c;写css 2、注册小程序&#xff0c;有个自己的appid&#xff0c;不用测试号了 5.1.注册小程序账号获取appid及个人和企业版差异_哔哩…

Python入门学习篇(六)——for循环while循环

1 for循环 1.1 常规for循环 1.1.1 语法结构 for 变量名 in 可迭代对象:# 遍历对象时执行的代码 else:# 当for循环全部正常运行完(没有报错和执行break)后执行的代码1.1.2 示例代码 print("----->学生检查系统<------") student_lists["张三",&qu…

vue3项目 - Eslint 配置代码风格

Eslint 自定义配置 总结&#xff1a; Prettier &#xff08;代码规范的插件&#xff0c;格式化 &#xff09;---> 美观 Eslint &#xff08;规范、纠错、检验错误 &#xff09;-----> 纠错 首先&#xff0c;禁用 Prettier 插件&#xff0c;安装 ESLint 插件&#x…