用Java语言编写一个简易画板
讲了三篇概博客的概念,今天,我们来一点实际的东西。我们来探讨一下如何用Java语言,编写一块简易的画图板。
一、需求分析
无论我们使用什么语言,去编写一个什么样的项目,我们的第一步,总是去分析这个项目需要满足怎样的需求。
那么,画板需要满足怎样的需要呢?换句话说,在画板上,我们应该赋予它什么功能呢?从我们熟悉的画板来看,我们需要实现诸如铅笔、橡皮、喷枪、刷子的功能,我们可以画出一些规则的图形,比如直线、矩形、圆。最好我们还能调整画笔的颜色和粗细。以上,我们希望的是,当我们点击一个按钮的时候,我们就能实现相对应的功能。一个简单画板的功能大概就这么多了,一些关于添加文本框、放大镜等的操作在简单画板上就不一一实现了。
二、实现画板
1、基本图形的绘制
我们先从最基本的画一些基本图形开始。在Java里有一个画笔类Graphics,而我们实现画板功能的关键就在这里。在Graphics这个画笔类里面,有几个方法,比如:画矩形、圆、直线。了解了这一点,我们的思路就来了。接下来,我们将一步一步认识实现基本图形绘制的全过程。
首先,我们需要实例化一个JFrame容器,并给它设置初始值。其次,我们需要在这个容器上,添加一些按钮。这里以直线、矩形、圆为例。这部分的实现比较简单,需要注意的是,我们可以通过实例化一个字符串类型的数组去存储按钮里的内容,然后通过遍历数组的方式去实现多个按钮的建立,以此减少代码行数。给出代码如下:
其次,因为涉及到关于鼠标点击以及按钮点击的操作,我们需要用到事件监听机制,MouseListener和ActionListener。因为它们都是接口,不能被实例化对象,所以我们需要建立一个事件处理类去实现这两个接口,并重写其中的抽象方法。具体代码如下:
当然,仅仅这样是不够的。首先,我们需要对事件源,也就是我们的按钮和画板界面通过addXXXListener的方式添加事件处理机制。其次,我们还需要对对应的方法,在其方法体中写上我们需要实现的功能。画笔类是一个抽象类,因此它是不能被实例化的,我们只能通过getGraphics这个方法从JFrame或者是JPanel里去获取画笔。注意,画笔的获取要在让界面可见之后。之后,因为我们在事件处理类里面要用到画笔,所以,我们还需要将画笔从我们的画板界面传到我们的事件处理类当中,我们可以在事件处理类里面定义一个setGraphics的方法,同时定义一个Graphics的引用去接收这个画笔。具体代码如下:
接下来就是调用画笔里的方法了。举个例子,当我们获取的按钮里的内容是Line的时候,那么,我们需要调用画笔Graphics里的drawLine方法,我们需要给它起始点和终点的x,y坐标。所以,我们在mousePressed方法里,记录下起始点的x,y坐标,在mouseReleased里记录下释放点的xy坐标,然后调用这个drawLine方法。那么,我们就可以在我们按下和释放的地方连成一条直线。代码实现如下:
这样我们就实现了三个基本图形的绘制。其他的, 在Graphics画笔类里面还有关于弧形、多边形、填充矩形等绘制方法,这里就不一一列举了。
2、画笔颜色与粗细的变化
Java里有一个Color类,它可以用作画笔颜色的设置。除了固定颜色的选取,例如Color.BLACK,我们程序员自己还可以自己去调取颜色。我们知道,每一种颜色,都可以由红、绿、蓝三基色按不同程度调配而成。在Java里有一个关于Color的构造方法,传入三个int类型、范围在0到255之间的数,分别对应红绿蓝三种颜色的程度。我们可以通过Color 颜色名=new Color(int a,int b,int c)的方式去自行定义自己想要的颜色。之后,我们可以通过.setColor的方式,将我们新建的颜色赋给我们的画笔。
而关于画笔粗细的设置方法,它并不在Graphics类里面,而是在它的子类Graphics2D里面。相较于Graphics,Graphics2D同样是一个抽象类,但是它里面新增了不少方法,比如给画笔设置粗细的方法setStroke。而在setStroke这个方法中,你所需要传递的参数是一个Stroke类型的参数,而Stroke是一个接口,所以不能够实例化,因此我们给它传递的是Stroke的一个封装类BasicStroke,它实现了Stroke这个接口。因此,我们设置粗细的方式为:(Graphics2D)g.setStroke(new BasicStroke(float width))。
如果我们需要实现这样的情况,在画板界面里有红、绿、蓝等多种颜色的按钮,当点击后画笔变成相应颜色,我们可以通过给按钮设置颜色的方式去处理这样的问题。给按钮或者窗体设置颜色的方式是.setBackground(Color c)。
3、铅笔、刷子、橡皮以及喷枪的实现
现在,我们知道了如何画一个圆,画一条直线。在实现铅笔等功能钱,我想先问个问题,如何去画一个点?我有两个想法,一个是,你可以通过画实心圆的方式来画一个点,给它半径指定为一个像素,那么所画出的实心圆就成了一个点。第二种,可以通过画直线的方式,指定起始位置和释放位置相同,那么画出的也是一个点。
接下来,我们要讲讲如何实现铅笔的功能。这里需要介绍一个新的事件监听方法,MouseMotionListener。在这个接口里,有一个鼠标拖动的监听方法。我们可以用它来实现铅笔的实现。它的工作机制是每隔一段时间,就获取一次你鼠标所在的位置。当然,这个时间非常短。事实上,我们可以观察在画图板上的直线。我们会发现每一条不规则曲线,都是由若干条直线构造而成的。那么,在这个拖动过程当中,我们可以在开始的地方记录下它的xy坐标,然后每运行一次拖动获取,就改变一次起始的xy坐标,那么,我们就实现了所谓的铅笔绘图功能。因为我们的事件处理类同时也继承了MouseListener,在拖动进行的开始,事实上我们已经进行了一次点击操作,所以,最开始的坐标我们不需要记录。注意,因为是不同的监听方法,所以一定要记得给画板界面添加MouseMotionListener的监听方法。铅笔的具体代码实现如下:
实现了铅笔,刷子其实也就那么回事,我们只需要将铅笔实现这部分的代码复制下来,并在之前添加一行给画笔加粗的代码即可,加粗了的铅笔,不就是我们的刷子吗?至于橡皮,我们也可以这么理解,只要找到与画板界面底色相类似的颜色,给画笔赋这样的颜色,不就能覆盖掉原有的部分了吗?
接下来是关于喷枪的实现。我们可以将喷枪理解成,在铅笔的基础上(去掉铅笔所绘的轨迹),对于一个点,在一定范围内,随机画若干个点。类似的变换,我们可以对一个点的xy坐标加减一定范围内不等的值,画出来的效果,就类似于喷枪效果了。生成随机数的方法在Random这个类里面,所以我们首先需要实例化一个Random类,然后通过nextInt(int a)的方式去获取一个0到a-1的随机数。这样,我们就能实现喷枪了。具体代码如下:
4、重绘
在这个实验过程当中,我们很容易发现一个问题,当我们最小化或者说调整窗体大小的时候,我们所绘制的图形消失了,然而按钮还在。这是为什么呢?事实上,每当我们进行一次最小化或者调整窗体大小的时候,我们原先的那个窗体都被关闭了,接着计算机又重新绘制了一个全新的窗体。所以,我们自行绘制的图形都没有了。那么,为什么我们的按钮还在?事实上,不仅仅是按钮,swing包内其他我们熟悉的组件,账号输入框、密码输入框等元素,也还是存在。事实上,每一个元素、每一个窗体,它都有一个重绘方法。当窗体改变大小的时候,生成新窗体后,计算机会调用这个重绘方法,所以你看到按钮等元素在改变界面后仍然在界面上。那么,如何让我们自行绘制的图形也像按钮一样,不会随着改变窗体而消失呢?
事实上,我们只需要重写一下画图界面上的重绘方法。这也就是为什么我要继承JFrame这个类的原因。因为继承了JFrame,所以,我们可以重写它继承的paint方法,在其中加上我们所绘制的内容,那么在窗体重绘的过程当中,我们所绘制的内容也就重新绘制上去了。
这只不过是重绘的第一步。因为我们绘制的内容有可能过于复杂,那么我们在主类里面如何去得知我们绘制了什么呢?我们可以定义一个shape类,然后在事件处理类里面定义一个shape类型的数组,每画一个图,那么,我们就用数组将它存储下来,然后让index++。为了简化paint方法里的内容,我们可以定义一个shape抽象类,里面定义一个抽象方法draw,然后申明不同图形,让它们都继承shape类,并且重写draw方法。这样,在paint方法里,我们就可以直接调用draw方法,而不用去写各种判断语句。这样做简化了我们的代码。
代码具体实现如下:
这里只给出shapeLine这个类的定义,关于其他类型的图案的定义就没有一一给出了,让看客自行发散。
5、进行界面的美化
假设我们把所有的按钮都如此加上,那么,我们会发现,画图界面会非常的不美观。为了增强界面的美观程度,我们可以通过引进panel的方法。我们可以将画基本图形的按钮放在一块面板内,颜色按钮放在一块面板里,而铅笔等功能又放到一块面板里。同时为了区分每个界面,我们还可以在重绘方法里,编写这样的语句g.drawLine来给界面加上边框。
完成程序,具备想要的功能只是第一步。之后我们需要做的就是去尽量让我们的界面美观,并且,一些能进行缩减的代码尽量缩减,使我们的代码看起来更加的精简干练。
三、总结
一个画板,说简单也简单,说复杂也复杂。以后我们打的程序肯定会越来越复杂,我们需要更加严谨,最好是加上一定的注释(当然我个人写代码是不喜欢写注释的,可能也是因为写的少的原因)。画板谈的比较粗糙,欢迎各位大神指正。
用Java语言编写一个简易画板的更多相关文章
- 使用Java语言编写一个五子棋UI界面并实现网络对战功能(非局域网)
使用Java语言编写一个五子棋UI界面并实现网络对战功能(非局域网) 一,前期准备 1,Java IDE(Eclipse)与JDK的安装与配置jdk-15.0.1-免配置路径版提取码:earu免安装版 ...
- 用java语言写一个简易版本的登录页面,包含用户注册、用户登录、用户注销、修改密码等功能
package com.Summer_0421.cn; import java.util.Arrays; import java.util.Scanner; /** * @author Summer ...
- 第二次作业利用java语言编写计算器进行四则运算
随着第一次作业的完成,助教 牛老师又布置了第二次作业:用java语言编写一个程序然后进行四则运算用户用键盘输入一个字符来结束程序显示统计结果.一开始看到这个题目我也着实吓了一跳 因为不知道如何下手而且 ...
- Fastjson是一个Java语言编写的高性能功能完善的JSON库。
简介 Fastjson是一个Java语言编写的高性能功能完善的JSON库. 高性能 fastjson采用独创的算法,将parse的速度提升到极致,超过所有json库,包括曾经号称最快的jackson. ...
- Atiitt 使用java语言编写sql函数或存储过程
Atiitt 使用java语言编写sql函数或存储过程 1.1. java编写sql函数或存储过程的机制1 1.2. Java编写sp的优点1 1.3. 支持java源码,class文件,blog f ...
- 使用java语言编写窗口按钮
使用java语言编写窗口按钮 代码如下: package Day08; import java.awt.FlowLayout; import javax.swing.JButton;import ja ...
- 用C语言编写一个简单的词法分析程序
问题描述: 用C或C++语言编写一个简单的词法分析程序,扫描C语言小子集的源程序,根据给定的词法规则,识别单词,填写相应的表.如果产生词法错误,则显示错误信息.位置,并试图从错误中恢复.简单的恢复方法 ...
- 基于OpenGL编写一个简易的2D渲染框架-06 编写一个粒子系统
在这篇文章中,我将详细说明如何编写一个简易的粒子系统. 粒子系统可以模拟许多效果,下图便是这次的粒子系统的显示效果.为了方便演示,就弄成了一个动图. 图中,同时显示了 7 种不同粒子效果,看上去效果挺 ...
- linux c语言编写一个shell壳
目的:我们要用c语言编写一个shell可以运行在linux机器上的. 介绍:shell所在的层次 我们要做的是操作系统,用于用户与操作系统进行交互的myhsell 思路:用户输入 一行字符串,我们先 ...
随机推荐
- Service基础使用
Service基础使用 之前的文章一直介绍Activity的使用,很多知识和用法单一的配合Activity使用,这次将总结Android四大组件之二--Service. 本文将要介绍以下内容: Ser ...
- 如何用TDR来测试PCB板的线路阻抗
隔壁小王已经讲了TDR的原理以及如何确定TDR的分辨率.那么,我们要正确测量PCB板上的线路阻抗,还有哪些需要注意的地方呢? 1. 阻抗测试的行业标准 之前贴过好多张阻抗测试的图片,重新再贴一张给大家 ...
- Android开发学习之路-带文字的图片分享
有用过微信分享SDK的都应该知道,微信分享到朋友圈的时候是不能同时分享图片和文字的,只要有缩略图,那么文字就不会生效.那么问题就来了,如果我们想把APP内的某些内容连带图片一起分享到微信,是不是没办法 ...
- Elasticsearch5.0 安装问题集锦
使用Elasticsearch5.0 必须安装jdk1.8 [elsearch@vm-mysteel-dc-search01 bin]$ java -version java version &quo ...
- Leetcode-268 Missing Number
#268. Missing Number Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find ...
- HTML5系列:HTML5与HTML4的区别
1. 语法的改变 1.1 DOCTYPE声明 DOCTYPE声明在HTML文件中必不可少,位于文件第一行. HTML4中声明方法: <!DOCTYPE html PUBLIC "-// ...
- Unity Shaders 第一个默认程序分析
Unity Shaders 第一个默认程序 Shader "Custom/Shader" { Properties { _MainTex ("Base (RGB)&quo ...
- 前端学PHP之文件操作
× 目录 [1]文件类型 [2]文件属性 [3]目录路径[4]目录遍历[5]目录统计[6]目录增删[7]目录复制[8]文件操作[9]文件内容 前面的话 在程序运行时,程序本身和数据一般都存在内存中,当 ...
- ueditor的配置和使用
ueditor下载好之后直接复制到项目的WebContent目录下,并将ueditor\jsp\lib下的jar包复制或者剪切到项目的lib目录下.先看一下效果,如下: 1.文件的上传 首先在uedi ...
- Web APi之EntityFramework【CRUD】(三)
前言 之前我们系统学习了EntityFramework,个人觉得有些东西不能学了就算完了,必须要学以致用,在Web API上也少不了增(C).删(D).改(U).查(R).鉴于此,我们通过EF来实现W ...