当我们写好一个简易画板,然后在上面画线,画圆等,再把窗口最小化,接着打开,你发现了什么??对,很神奇的事发生了,不是在做梦,之前的所有图形全部消失了,why??原来, 当窗体在屏幕上显示时,首先是将窗体对象的数据从内存中取出来放到缓存中,再在屏幕上进行绘制。当窗体发生改变的时候,程序会重新从内存中获取更新后的数据绘制。all effort are in vain!那怎么办呢?嗯嗯,方法当然是有的啦,就是重绘!!
通过重写JFrame类的paint(Graphics g)方法来保存我们画过的形状,大概就是下面这么个过程:
1)创建保存形状的队列(采用泛型)
2)每绘制一个形状,就将绘制过的形状保存到队列。
这里就要提到图形类,其实就是创建一个图形的类,里面有画这个图形的方法啦。不过在此前,要创建一个抽象的Shape类,让图形类去继承它;因为要创建很多图形类嘛,哈哈。
之后呢要在事件源上的g(Graphics类)进行重写paint()方法,把队列中存储的图形全部绘制出来,这样就搞定啦。不过要提醒的是,如果是在窗体上进行重写paint()方法,图形可能会越界到其他面板上哦!!
大概的代码如下:
首先是实现类:
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JColorChooser; import javax.swing.JFrame; import javax.swing.JPanel; public class Draw { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub //实例化一个画板对象 Draw sd=new Draw(); //调用显示画板的方法 sd.showUI(); } public void showUI() { /* * 实例化一个窗体对象 */ JFrame jf=new JFrame(); jf.setTitle("普通画板");//设置窗体标题 jf.setSize(600,500);//设置窗体大小 jf.setLayout(new BorderLayout());//设置窗体布局为边框布局 jf.setResizable(false);//禁止窗体改变大小 jf.setLocationRelativeTo(null);//设置窗体居中 jf.setDefaultCloseOperation(3);//设置关闭窗体关闭程序 //调用创建北边面板方法 JPanel northpanel=creatNorthPanel(); //将面板添加到窗体上 jf.add(northpanel,BorderLayout.NORTH); //调用创建中间面板方法 JPanel centerpanel=creatCenterPanel(); //将面板添加到窗体上 jf.add(centerpanel,BorderLayout.CENTER); jf.setVisible(true);//设置窗体为可见 // 先让窗体可见,再弄下面的程序!!!!!!!!!!!!!!!!!!!!!!!! Graphics g=centerpanel.getGraphics();//从中间面板中接收Graphics对象 DrawListener ml=new DrawListener(g,this);//实例化一个DrawListener类对象 //给中间面板添加动作监听器,绑定MouseListener事情处理类对象 centerpanel.addMouseListener(ml); //给中间面板添加动作监听器,绑定MouseMotionListener事件处理类对象 centerpanel.addMouseMotionListener(ml); } private String str="Line";//定义一个存储图像的属性值 /* * 获得存储图像的属性 */ public String getStr() { return str; } private Color color;//定义颜色的属性值 /* * 获得颜色的属性 */ public Color getColor() { return color; } /* * 创建北边面板的方法 */ public JPanel creatNorthPanel() { JPanel north_panel=new JPanel();//实例化北边面板的对象 //设置北边面板的属性 north_panel.setPreferredSize(new Dimension(500,100));//设置北边面板大小 north_panel.setLayout(new FlowLayout(FlowLayout.LEFT));//设置北边面板布局为流式布局,并向左对齐 //匿名,实现ActionListener接口 ActionListener al=new ActionListener() { //事情发生类方法 public void actionPerformed(ActionEvent e) { //判断是否点击到"Color"按钮 if(e.getActionCommand().equals("Color")) { //弹出一个颜色选择器,供选择颜色;选择好的颜色返回color color=JColorChooser.showDialog(null, "颜色选择器", Color.BLACK); } else {//获取按钮上的文本 str=e.getActionCommand();//将获得的字符赋给字符串str } } };//注意加“;”!!!!!!!!!!!!!!!!!! //创建一位数组,储存按钮上的文本 String []array={"Line","Rectangle","Oval","RoundRect","Polygon","Pencil","Color","Eraser","Brush","Gunjet"}; // 遍历数组,创建按钮,并添加文本在按钮上 for(int i=0;i<array.length;i++) { JButton jb=new JButton(array[i]);//实例化按钮对象 jb.setPreferredSize(new Dimension(100,40));//设置按钮大小 //给事件源添加动作监听器方法,绑定事件处理类对象 jb.addActionListener(al); north_panel.add(jb);//将按钮添加到北边面板上 } return north_panel; } /* * 创建中间面板的方法 */ public JPanel creatCenterPanel() { JPanel center_panel=new JPanel(){ //重写paint()方法 public void paint(Graphics g) { super.paint(g);//调用父类的paint()方法 //绘制存储的图形 for(int i=0;i<DrawListener.list.size();i++) { Shape shape=DrawListener.list.get(i);//获取存储图像类 shape.draw(g);//调用图形类绘制方法 } } };//实例化中间面板的对象 center_panel.setBackground(Color.WHITE);//设置面板的背景色 return center_panel; } }
然后是数组队列的创建:
import java.util.Collection; public interface SelfArrayList <E>{ public void add(E e);//向队列尾部添加元素方法 public boolean remove(E e);//移除此列表中首次出现的指定元素(如果存在) public E get(int index);//取得队列中指定位置的一个对象 public int size();//得到队列长度 public void add(int index, E e); //将指定的元素插入此列表中的指定位置。 public boolean addAll(Collection<? extends E> c);//按照指定 collection 的迭代器所返回的元素顺序,将该 collection 中的所有元素添加到此列表的尾部。 public void clear();// 移除此列表中的所有元素 public int indexOf(E e);//返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。 public boolean isEmpty();//如果此列表中没有元素,则返回 true public int lastIndexOf(E e);//返回此列表中最后一次出现的指定元素的索引,或如果此列表不包含索引,则返回 -1。 public E set(int index, E e);// 用指定的元素替代此列表中指定位置上的元素。 public E remove(int index);//移除此列表中指定位置上的元素。 }
然后是Shape的抽象类:
import java.awt.Color; import java.awt.Graphics; public abstract class Shape { private int x1,x2,y1,y2;//定义坐标属性 private Color color;//定义颜色属性 private int width;//定义宽度属性 private int height;//定义高度属性 //构造方法 public Shape(int x1,int x2,int y1,int y2,Color color,int width,int height) { this.x1=x1; this.x2=x2; this.y1=y1; this.y2=y2; this.color=color; this.width=width; } public void draw(Graphics g) { } public void setx1(int x1) { this.x1=x1; } public int getx1() { return x1; } public void setx2(int x2) { this.x2=x2; } public int getx2() { return x2; } public void sety1(int y1) { this.y1=y1; } public int gety1() { return y1; } public void sety2(int y2) { this.y2=y2; } public int gety2() { return y2; } public void setColor(Color color) { this.color=color; } public Color getColor() { return color; } public void setWidth(int width) { this.width=width; } public int getWidth() { return width; } public void setHeight(int height) { this.height=height; } public int getHeight() { return height; } }
然后是各种图形类,这里就只放一个直线类和橡皮擦类啦:
import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; /* * 直线的图形类 */ public class ShapeLine extends Shape { //继承的子类要和父类有同一套构造方法 public ShapeLine(int x1, int x2, int y1, int y2, Color color, int width) { super(x1, x2, y1, y2, color, width, width); // TODO Auto-generated constructor stub } //画直线的方法 public void draw(Graphics g) { g.setColor(this.getColor());//设置图形颜色 Graphics2D g2=(Graphics2D)g;//强制转型,把Graphics类型转换成Graphics2D类型 g2.setStroke(new BasicStroke(this.getWidth()));//设置线条粗细 g2.drawLine(getx1(), gety1(), getx2(), gety2());//画直线 } }
import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; public class ShapeEraser extends Shape { public ShapeEraser(int x1, int x2, int y1, int y2, Color color, int width, int height) { super(x1, x2, y1, y2, color, width, height); // TODO Auto-generated constructor stub } public void draw(Graphics g) { g.setColor(this.getColor());//设置白色颜色 Graphics2D g2=(Graphics2D)g;//强制转型 //设置笔的粗细为2.0F,线条端点是CAP_ROUND,点划线模式为 JOIN_ROUND g2.setStroke(new BasicStroke(10.0F,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND)); g2.drawLine(getx1(),gety1(),getx2(),gety2()); g2.setStroke(new BasicStroke()); } }
最后是事件监听器:
import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.Random; public class DrawListener implements MouseListener ,MouseMotionListener { private int x1,x2,y1,y2;//记录鼠标两次点击的坐标 private Graphics g;//从界面对象上得到的画布对象 private Graphics2D gg; private Draw sd; private int flag=1; public int m,n; public int x3,y3,x4,y4; private int m1=0,n1=0; //创建一个数组队列,存储图像类 public static UseArrayList<Shape> list=new UseArrayList<Shape>(); //构造方法,用来接收Graphics对象和Draw类对象 public DrawListener(Graphics g,Draw sd){ this.g=g; this.sd=sd; } //鼠标按下的点的坐标 public void mousePressed(MouseEvent e){ //记录第一次点击的x,y:通过事件对象e得到的 x1=e.getX(); y1=e.getY(); //获得点击“Polygon”时初次点击的点的坐标 if(sd.getStr().equals("Polygon")) { x3=e.getX(); y3=e.getY(); flag++; if(flag==2) { m=x3; n=y3; x4=m; y4=n; } } //判断鼠标是按左键还是右键 if(e.getButton()==1) { //按左键,颜色为sd得到的黑色 g.setColor(sd.getColor()); } else if(e.getButton()==3) { //按右键,颜色为绿色 g.setColor(Color.GREEN); } } //鼠标释放时的坐标 public void mouseReleased(MouseEvent e) { //记录第二次点击时的坐标 x2=e.getX(); y2=e.getY(); //判断是否为Line if(sd.getStr().equals("Line")) { // //调用画布对象的方法,画直线 // g.drawLine(x1,y1,x2,y2); Shape shapeLine=new ShapeLine(x1,x2,y1,y2,Color.BLACK,1); shapeLine.draw(g); list.add(shapeLine);//将直线类添加到队列上 } /* * 判断是否为矩形Rectangle */ if(sd.getStr().equals("Rectangle")) { // g.drawRect(Math.min(x1, x2), Math.min(y1, y2),Math.abs(x1-x2), Math.abs(y1-y2));//Math.min(x1, x2), Math.min(y1, y2)! Shape shapeRectangle=new ShapeRectangle(x1,x2,y1,y2,Color.BLACK,1,4); shapeRectangle.draw(g); list.add(shapeRectangle);//将矩形类添加到队列上 } /* * 判断是否为椭圆形Oval */ if(sd.getStr().equals("Oval")) { // g.drawOval(x1, y1,Math.abs(x1-x2) , Math.abs(y1-y2)); Shape shapeOval=new ShapeOval(x1,x2,y1,y2,Color.BLACK,1,4); shapeOval.draw(g); list.add(shapeOval);//将椭圆类添加到队列上 } /* * 判断是否为RoundRect */ if(sd.getStr().equals("RoundRect")) { // g.drawRoundRect(x1, y1, Math.abs(x1-x2),Math.abs(y1-y2), Math.abs(x1-x2)/2,Math.abs(y1-y2)/2 ); Shape shapeRoundRect=new ShapeRoundRect(x1,x2,y1,y2,Color.BLACK,1,4); shapeRoundRect.draw(g); list.add(shapeRoundRect); } /* * 判断是否为Polygon */ //获取拖动过程中的坐标值 int x = e.getX(); int y = e.getY(); if(sd.getStr().equals("Polygon")) { //判断鼠标点击的坐标是不是与第一次点击的一样,不同则画线 if((x!=m)||(y!=n)) { // //画线 // g.drawLine(x4, y4, x, y); Shape shapePolygon=new ShapePolygon(x4,x,y4,y,Color.BLACK,1,4); shapePolygon.draw(g); list.add(shapePolygon); //赋值 x4=x; y4=y; } // Shape shapePolygon=new ShapePolygon(x4,y4,x,y,Color.BLACK,1,4); // shapePolygon.draw(g); // list.add(shapePolygon); } } /* * 当鼠标在事件源上单击时按键执行的方法 */ public void mouseClicked(MouseEvent e) { if(sd.getStr().equals("Polygon")) { //获取点击过程中的坐标值 int x = e.getX(); int y = e.getY(); //如果双击鼠标,当前的点会与初始点连线 if(x==m1&&y==n1) { // g.drawLine(x, y, m, n); Shape shapePolygon=new ShapePolygon(x,m,y,n,Color.BLACK,1,4); shapePolygon.draw(g); list.add(shapePolygon); flag=1;//使flag归为1,便能改变再次画多边形时的第一次单击的坐标值 } m1=e.getX(); n1=e.getY(); } } public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} /* * 当鼠标在事件源上拖拉时按键执行的方法 */ public void mouseDragged(MouseEvent e) { //判断点击的按钮是否为"Pencil" if(sd.getStr().equals("Pencil")) { //获取x,y的坐标值 int x=e.getX(); int y=e.getY(); // //画线 // g.drawLine(x1, y1, x, y); Shape shapePencil=new ShapePencil(x1,x,y1,y, Color.BLACK, 1, 4); shapePencil.draw(g); list.add(shapePencil); //赋值 x1=x; y1=y; } /////////////////////////////////////////////////////////////////////////////////////////////////////// //判读点击的按钮是否为"Eraser" if(sd.getStr().equals("Eraser")) { //获取x,y的坐标值 int x=e.getX(); int y=e.getY(); // //设置线条为白色 // g.setColor(Color.WHITE); // //画线 // gg =(Graphics2D)g; //实例化一个Graphics2D对象 // //设置笔的粗细为2.0F,线条端点是CAP_ROUND,点划线模式为 JOIN_ROUND // gg.setStroke(new BasicStroke(10.0F,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND)); // gg.drawLine(x1,y1,x,y); // gg.setStroke(new BasicStroke()); Shape shapeEraser=new ShapeEraser(x1,x,y1,y,Color.WHITE,1,4); shapeEraser.draw(g); list.add(shapeEraser); //赋值 x1=x; y1=y; } /////////////////////////////////////////////////////////////////////////////////////////////////////// //判读点击的按钮是否为"Brush" if(sd.getStr().equals("Brush")) { //获取x,y的坐标值 int x=e.getX(); int y=e.getY(); // //设置线条为选择的颜色 // g.setColor(sd.getColor()); // //画线 // gg =(Graphics2D)g; //实例化一个Graphics2D对象 // //设置笔的粗细为2.0F,线条端点是CAP_ROUND,点划线模式为 JOIN_ROUND // gg.setStroke(new BasicStroke(10.0F,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND)); // gg.drawLine(x1,y1,x,y); // gg.setStroke(new BasicStroke()); Shape shapeBrush=new ShapeBrush(x1,x,y1,y,Color.BLACK,1,4); shapeBrush.draw(g); list.add(shapeBrush); //赋值 x1=x; y1=y; //////////////////////////////////////////////////////////////////////////////////////////// } //判读点击的按钮是否为"Gunjet" if(sd.getStr().equals("Gunjet")) { //获取x,y的坐标值 int x=e.getX(); int y=e.getY(); int x0=0; int y0=0; // //设置线条为黑色 // g.setColor(sd.getColor()); // //噴槍大小 // int size=8; // //噴槍点數 // int count=10; // for(int i=0;i<count;i++) // { x0 = new Random().nextInt(size)+ 1; // y0 = new Random().nextInt(size) + 1; // g.fillRect(x+x0, y+y0,5,5); // } Shape shapeGunjet=new ShapeGunjet(x1,x,y1,y,Color.BLACK,1,4); shapeGunjet.draw(g); list.add(shapeGunjet); } } /* * 事件源上移动鼠标的方法 */ public void mouseMoved(MouseEvent e) { } }
这样就基本完成啦,然后至于对界面的美好等就需要继续努力咯!!
相关推荐
易语言画板自绘源码,画板自绘,标尺子程序_绘制标尺刻度,恢复鼠标状态,无拖动时激活恢复,刻度区重绘,客户区重绘,二级缓冲绘制,客户区刷新,选中辅助线,高亮辅助线,拖动辅助线,客户绘制的图形,GetProp,SetRect,SetProp,...
易语言画板自绘列表框源码,画板自绘列表框,重画列表,取现行选中项,加入表项,取现行选中项备注
易语言画板自绘列表源码,画板自绘列表,重画,挂接,置行高,进度,取表项数,插入项目,更新进度,取选中项,删除表项,取项名称,取项软件大小
在VS2015环境下,利用MFC框架实现的一款高仿“画图”工具,实现绝大部分功能甚至更多创新点。(注释超详细) 实现了点、直线、曲线、折线、矩形、圆形、多边形等等形状,并且具有区域限制、鼠标捕捉等功能;...
可以自由画线,设置线宽,绘画...添加新图片、保留原图片、自由选择某个图片的操作、可以撤销、重绘、添加背景、编写文字描述.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
(6)新建文件功能:新建文件,将画板上绘制的内容清空(清空之前可以确认是否需要进行保存)清屏(重绘)功能依次方法; (7)文件保存格式为BMP格式; (8)文字功能:读取文本框中的文本并打印到屏幕鼠标的相应的响应...
将其画板位图进行重绘,清空画布。4.撤销模块。保存其画笔路径,撤销时删除上一步操作,调用重绘来实现。5.保存绘图模块。先在本地的文件夹上创建一个文件 默认创建的是/sdcard/Pictures/由于文件的名字是不能重复的...
一个模仿了画板涂鸦的小demo.基本的重绘实现了.实现了颜色的变化和笔记粗细的变化
OpenGL ES之手写绘画板:详细的实现了PaintView的画笔的颜色、尺寸、笔触等设定切换,并运用OpenGL ES自定义着色器实现画板曲线的绘制,并实现了重做、重绘、橡皮擦、撤销、清除等逻辑的实现。
包含图像重绘,迭代图像,递归图形等全功能的创意画板
易语言自绘画板编辑框源码,自绘画板编辑框,编辑_加入高亮文本,系统_光标绘画,系统_修改光标闪烁速度,系统_取文本高宽,初始化文本行数据,系统_窗口回调,数据_文本行数据重置,系统_值当前段,系统_重画文本,取高16位,...
1. 实现编写的一个重绘接口。 2. 在用户界面 GUI 类中,继承 JFrame 类. 3. 在事件监听 DrawListener 类中实现了 MouseListener、MouseMotionListener、 ActionListener 监听接口,并重写其绘图方法。 4.在事件监听...
本例 1.有对edit重绘,实现画板的功能 2.进度条重绘 比网上流传的老外写的效率高,由于设置背景模式为透明,产生的百分比会模糊,网上那个效率比较的低,一直在重绘,还好是c++速度快
大概思路1.申请空间存放组件xx,使用__set(),__get(),__quary(),__add(),__del()等汇编操作提高...3.需要重画的组件才重画,提高效率 4.用常量来标识各类状态,方便修改 (e比较蛋.疼的地方,就是没有鼠标移入移出事件...)
win32实现画图小程序,主要功能:画直线、矩形、椭圆,曲线,画板清除,重绘,颜色选择,工具选择,调色板和工具栏的隐藏和显示,调色板的停靠,文件保存和打开
易语言迷你工具箱源码,迷你工具箱,绘_画板_移动鼠标,绘_取索引,绘_画项目,绘_画热点,绘_画焦点,绘_重画,绘_重画项目,绘_画板_按下左键,绘_文本写出位置,创建事件同步对象,打开事件同步对象
易语言迷你工具箱2.21源码,迷你工具箱2.21,绘_画板_移动鼠标,绘_取索引,绘_画项目,绘_全部重画,绘_重画项目,绘_画板_按下左键,绘_文本位置,创建事件同步对象,打开事件同步对象
使用UIBezierPath 简单实现的画板,实现了后退,前进,橡皮擦,清空画布,保存到系统...整体绘制导致CPU占用过高,这边采用了局部重绘。 通过中点绘制贝塞尔二阶曲线,优化拐角锯齿问题(通过快速打对勾即可看出效果)