Hello,大家好,这是我的第二篇博客,写的是如何创作一个画图板;因为我以前写的代码都是用dev-C++写的控制台程序,这次学习了JFrame等容器,就想写个画图工具练练手,这一篇我讲的可能会细碎一点。
首先我们要做一个可视化界面,用JFrame类即可,JFrame是一个窗体类,就是我们平时见到的窗体框架,当我们实例化一个JFrame对象时,相当于就是创造了一个窗体,具体的窗体实现我就不在这里详述了,可以看其他博客或者私我。
要做一个画图板,首先要做一个窗体,代码如下:
package Paint_10_28;
import javax.swing.*;
public class Test_Paint {
public static void main(String[] args) {
//创建窗体
JFrame jf =new JFrame();
//设置窗体名字
jf.setTitle("画图板");
//设置窗体大小
jf.setSize(600,600);
//设置窗体居中
jf.setLocationRelativeTo(null);
//设置窗体可见
jf.setVisible(true);
//设置默认关闭形式
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
至此,我们即已经做好了一个简单的窗体程序,接下来我们要在窗体上添加各种功能,比如画画功能,比如重绘功能(后面会详细介绍),比如改变画笔颜色,比如画各种图形,比如清除画板等等。
实现画画功能:
我们要实现画画第一点要想到的是,假设我们要画一条直线,一般是按紧鼠标拖动一段距离,松开鼠标的时候直线便会从起点处画到终点处,我们是不是需要一个鼠标的监听事件呢,对了,就是要监听鼠标的动作,那就需要将JFrame调用addMouselistener,然鹅addMouseListener方法需要一个MouseListener对象作参数,问题又来了,这个MouseListener是一个接口,无法直接实例化对象(详情可参照上一篇博客),这个我们可以新建一个监听的类,在Buttonlistener类中我们实现MouseListener接口,这样子就可以实现对鼠标的监听了(当然要记得重写接口中的方法喔)
第二点要想到的是,如何获取一个画笔来画出图形。在Java中,有一个画笔类,我们只需要实例化画笔对象即可,而画笔对象不是new出来的,我们需要用一个JFrame或者JPanel对象来获取。
形如:JFrame jf = new JFrame();//创建窗体对象
Graphics gf = jf.getGraphics();//通过窗体对象来获得一个画笔
上代码
package Paint_10_28;
import java.awt.event.*;
import javax.swing.JPanel;
public class ButtonListener implements ActionListener,MouseListener,MouseMotionListener {
private JPanel jp;
private Graphics gr;
int x1=0,y1=0,x2=0,y2=0;
// Override鼠标监听//点击
public void mouseClicked(MouseEvent e) {
}
@Override // 按下
public void mousePressed(MouseEvent e) {
//鼠标按下的时候,分别获取起点的横纵坐标
x1=e.getX();
y1=e.getY();
}
@Override // 松开
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
//鼠标松开的时候,分别获取终点的横纵坐标
x2 = e.getX();
y2 = e.getY();
gr.drawLine(x1, y1, x2, y2);//通过drawLine方法在两个点之间连一条直线(gr是画笔)
}
@Override // 进入
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override // 移出
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
前面我们讲述了如何生成窗体并让鼠标画线,但是我们的画笔一直是现成的,要生成一个画笔我们用如下代码
JPanel jp = new JPanel();
Graphics gf = jp.getGraphics();
有了窗体,鼠标监听和画笔,我们就可以画图了,效果图如下
大家刚刚看到我的效果图上面有很多按钮可以控制画不同的线,其实是我添加了很多按钮在面板上面,前面讲过添加MouseListener,如果要用到按钮的话,就要用某个按钮addActionListener,这样子按钮就可以监听到我们的行动,伪代码如下:
JBuuton jb = new JButton("直线");
/*大家看到下面的函数中用了ActionListener的对象,但是这是个接口,不能实例化对象,因此实际的代码中要用他子类的对象才可以,在这里是伪代码就不细说了,当然还涉及到接口方法的重写,这个上一篇博客有写*/
jb.addActionListener(ActionListener e)
有了按钮之后,我们就可以通过按钮来设定不同的线条和画笔颜色,这些多种功能可以自己后期去实现,讲到现在为止,我们的画板已经可以画直线了,实现到这一步,我们发现如果把窗体拉大或者缩小,或者将窗口最小化再最大化画板上的内容会消失
画板的内容消失这不是我们所期待的,我们要怎么处理呢,这里就涉及到窗体的重绘机制,其实我们的窗体在发生大小变化时,会默认自动调用一个函数叫做paint(),如果我们要想自己画的东西不消失,就要重写paint方法,让他在重绘窗体的时候把我们的图形也画进去,那么一个最简单的想法,我们可以建立一个数组,将我们所有绘画的图案存进去然后在调用paint方法的时候,我们除了绘画窗体还要用一个for循环,将数组内部的图案取出来,画在画板上。伪代码如下:
public void paint(Graphics g) {
//调用super.paint(),因为要先画出窗体,再重绘我们的图案
super.paint(g);
len = btl.get_len();
for(int i=0;i
//这里是上面调用的repaint方法
public void repaint(Graphics g) {
//在这里进行
g.drawLine(x1, y1, x2, y2);
}
这样子过来,我们就已经基本上实现了
1.构建窗体
2.添加鼠标监听
3.获取画笔画图案
4.添加按钮监听用来控制画板
5.添加重绘机制,让图案不消失
上面的所有代码都是伪代码,合起来并不能实现一个真正的画板,下面上源代码
敲黑板,需要源代码的自取喔,总共三个文件
Shape类,能存放不同的图案
package Paint_10_28;
import java.awt.Graphics;
import javax.swing.JPanel;
//定义一个图案的类,方便对多种图案进行实现和管理
public class Shape{
//Shape类有name和两点坐标的属性
private int x1,x2,y1,y2;
private String name;
public Shape(int x1,int y1,int x2,int y2,String name){
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
this.name = name;
}
//根据不同的图案名字,开展不同的重绘机制
public void repaint(Graphics g) {
switch(name) {
case "直线":
g.drawLine(x1, y1, x2, y2);
break;
case "矩形":
g.drawRect(Math.min(x1, x2), Math.min(y1 ,y2), Math.abs(x1-x2), Math.abs(y1-y2));
break;
case "圆形":
g.drawOval(Math.min(x1, x2), Math.min(y1 ,y2), Math.abs(x1-x2), Math.abs(y1-y2));
break;
case "曲线":
g.drawLine(x1, y1, x2, y2);
break;
case "多边形":
g.drawLine(x1, y1, x2, y2);
break;
}
}
}
ButtonListener类,监听类,继承了多个接口,可以实现多种监听
package Paint_10_28;
import java.awt.event.*;
import javax.swing.JButton;
import javax.swing.JPanel;
public class ButtonListener implements ActionListener,MouseListener,MouseMotionListener {
private int index=0;
private Shape ShArr[];
private JPanel jp;
private java.awt.Graphics gr;
private String zhiling="";
int x0=0,y0=0,x1=0,y1=0,x2=0,y2=0,x3=0,x4=0,y3=0,y4=0,start_x=0,start_y=0;
public void set_jp(JPanel jp) {
this.jp=jp;
}
public void set_gr(java.awt.Graphics G) {
this.gr = G;
}
public void set_ShArr(Shape ShArr[]) {
this.ShArr = ShArr;
}
public int get_len() {
return index;
}
public void actionPerformed(ActionEvent e)
{
// TODO Auto-generated method stub
x1 = 200; y1 = 200;
if (e.getActionCommand()=="") {
JButton j = (JButton)e.getSource();
gr.setColor(j.getBackground());
}
else {
zhiling = e.getActionCommand();
if("清除".equals(zhiling)) {
//System.out.println("这里是buttonlistener的清除");
index = 0;
// p.set_len(len);
jp.repaint();
x4 = 0;
y4 = 0;
}
}
}
//鼠标拖动时间,用来绘画曲线
public void mouseDragged(MouseEvent e) {
//System.out.println("Drag");
if("曲线".equals(zhiling)) {
x1 = x0; y1 = y0; x0 = e.getX(); y0 = e.getY();
gr.drawLine(x1,y1,x0,y0);
ShArr[index++] = new Shape(x1,y1,x0,y0,zhiling);
}
}
// Override鼠标监听//点击鼠标点击时间,用来绘画多边形
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
if("多边形".equals(zhiling)) {
if(x4==0&&y4==0){
x4 = e.getX(); y4 = e.getY();
start_x = x4; start_y = y4;
//gr.drawLine(x3, y3, x4, y4);
}
else {
//System.out.println("Here is duobianxing ");
x3 = x4; y3 = y4; x4 = e.getX(); y4 = e.getY();
gr.drawLine(x3, y3, x4, y4);
ShArr[index++] = new Shape(x3,y3,x4,y4,zhiling);
}
if(e.getClickCount()==2){
//System.out.println("双击");
//System.out.println("双击");
x4 =0; y4=0;
gr.drawLine(start_x, start_y, e.getX(), e.getY());
ShArr[index++] = new Shape(start_x,start_y,e.getX(),e.getY(),zhiling);
}
}
}
//当鼠标按下的时候,获取起点的坐标
@Override // 按下
public void mousePressed(MouseEvent e) {
// System.out.println("按下");
if("曲线".equals(zhiling)){
x0 = e.getX();
y0 = e.getY();
}
// TODO Auto-generated method stub
x1 = e.getX();
y1 = e.getY();
}
//当鼠标松开的时候,获取终点的坐标
@Override // 松开
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
x2 = e.getX();
y2 = e.getY();
// System.out.println("松开");
if("直线".equals(zhiling)){
gr.drawLine(x1, y1, x2, y2);
ShArr[index++] = new Shape(x1,y1,x2,y2,zhiling);
//System.out.println("长度是 "+len);
}
else if("矩形".equals(zhiling)) {
gr.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1-x2), Math.abs(y1-y2));
ShArr[index++] = new Shape(x1,y1,x2,y2,zhiling);
}
else if("圆形".equals(zhiling)) {
gr.drawOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1-x2), Math.abs(y1-y2));
ShArr[index++] = new Shape(x1,y1,x2,y2,zhiling);
}
}
//剩下的方法,可以暂时不用管
@Override // 进入
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override // 移出
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseMoved(MouseEvent e) {
}
}
paint类,主函数所在的类,里面实例化了窗体对象,重写了paint方法
package Paint_10_28;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Paint extends JPanel{
//建立一个很大的数组,用来存放图形元素
private Shape[] ShArr = new Shape[10000];
public static void main(String[] args) {
Paint p = new Paint();
}
JFrame jf = new JFrame();
//JPanel jp = new JPanel();
int len = 0;
//实例化一个ButtonListener对象,实现了多种接口
ButtonListener btl = new ButtonListener();
public Paint() {
//实现一个窗体
jf.setTitle("画图板");
jf.setLocation(450, 100);
jf.setSize(700, 600);
this.setPreferredSize(new Dimension(600, 500));
//声明两个数组,包含各种指令
String[] command = { "开始", "清除", "直线", "曲线", "多边形", "矩形","圆形" };
Color[] color = { Color.BLACK, Color.BLUE, Color.YELLOW, Color.RED, Color.GREEN };
//设置布局为流式布局
jf.setLayout(new FlowLayout());
/*在下面的两个循环中将各种按钮添加进入动作监听器中,其中addActionListener参数为btl,
btl是一个Buttonlistener的对象
*/
for (int i = 0; i < command.length; i++) {
JButton jb = new JButton(command[i]);
jb.addActionListener(btl);
jf.add(jb);
}
for (int i = color.length - 1; i >= 0; i--) {
JButton jb = new JButton();
jb.setBackground(color[i]);//设置背景颜色
Dimension dm = new Dimension(20, 20);//设置大小
jb.setPreferredSize(dm);
jb.addActionListener(btl);
jf.add(jb);
}
//将JPanel对象添加进入jf窗体对象中,让他生效
jf.add(this);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true); //设置可见
Graphics gf = this.getGraphics(); //获取画笔,我们的this代表当前类的对象,正好是一个JPanel的对象
this.addMouseListener(btl); //添加鼠标监听器,用于画图
this.addMouseMotionListener(btl); //添加鼠标模式监听器,用于绘画曲线
btl.set_gr(gf); //设置另外一个类的画笔
btl.set_jp(this); //设置另外一个类的JPanel容器
btl.set_ShArr(ShArr); //设置另外一个类的数组
}
public void paint(Graphics g) {
super.paint(g); //调用父类的paint方法,用来画出窗体
len = btl.get_len(); //获取数组的长度
//重绘我们的图案
for(int i=0;i
这三个类是画图板的主要组成部分,需要的同学可以自取。画图板中间许多比较复杂的功能我并没有解释的很清楚,只是给出了一个大体的思路,对源代码有疑问的可以mail【[email protected]】这个画图板搞了我三天时间,通过这画图板我对各种监听和继承有了更深的理解,另外一点重要的理解是,Java中不同的类之间不方便共享数据,但是他可以共享类的对象,因此我们要共享数据可以通过将某个类的对象当做参数传递过去,然后通过getxxx()方法来获取那个类中的某个数据,在这个画图板中,图案数组的长度我就是这样处理的。
最后效果图如下
/写的比较糙,有什么疑问的可以发邮件给我,欢迎大家批评指正***/