一、为什么要重绘
1、计算机有三种存储数据的存储器--外存、内存和缓存。缓存就是计算机里的硬盘,外存的特点 是可以永久地保存数据(在硬盘不会损坏的情况下),它的缺点是:存储数据和读取数据的速度 很慢。内存是介于外存与缓存之间,计算机所要运行的所有程序,必须先从外存读取到内存中, 这当然也包括操作系统。还有内存在通电状态下才有保存数据的作用,如果计算机的电源关闭了 ,内存里的数据也会消失,所以我们在做一些重要的文档时要及时保存数据,这里的保存是将内 存里的数据保存到外存里,也就是硬盘上。缓存是CPU上的一块存储器,它是用来临时保存CPU马 上要处理的数据,一旦里面的数据不需要了,缓存就会马上被清空。
2、我们在画图板上画的图形,它的数据是被临时保存在缓存里的,当我们把窗口最大化或最小化, 或其他的操作是,缓存里的数据就会被清空。而当我们再把窗口还原是,窗口的数据会重新从内存读 到缓存里,经过处理后吧窗体显示,但是因为我们没有把我们画的图形的数据保存起来,所以当窗体 重新显示时,我们之前画的图形并没有显示。所以要让我们画的图形能够重新显示,我们必须把图形 的数据保存起来。
二、重绘的方法
1、用队列来保存数据 队列是用来保存数据的一种数据结构,它相当于一个动态数组,所以我们可以用它来保存我们 在画图板上所画的图形的数据。思路就是我们每画一个图形,就把它保存到队列里去,当需要重 绘时,只需要把队列里的数据重新取出来,把它画到画图板上。
下面是我自定义的保存图形数据 的队列:
public class mylist<E> { //将数组定义为Object数组,表示能存放Java中所有的对象 private Object[] src = new Object[0]; /** * 将指定的数据放入队列容器中 * * @param e * 要放入队列容器的数据 */ public void add(E e) { //定义一个新数组,长度是原始数组长度+1 Object dest[] = new Object[src.length+1]; //将新元素放入新数组最后一个下标位置 dest[src.length] = e; //将原始数组中的元素按照下标顺序拷贝到新数组 for(int i=0;i<src.length;i++){ dest[i] = src[i]; } //将原数组名指向新数组 src = dest; } /** * 取出指定下标位置的元素 * * @param index * 要取出的元素的下标 * @return 返回取得的元素 */ public E get(int index) { //得到src对应下标的元素 E e = (E)src[index]; return e; } /** * 删除指定位置的元素 * * @param index * 要删除的元素的下标 */ public void delete(int index) { //创建一个长度比src小1的数组 Object [] arr =new Object[src.length-1]; //拷贝下表之前的元素 for(int i=0;i<index;i++){ arr[i]=src[i]; } //拷贝下标之后的元素 for(int j=index;j<src.length;j++){ arr[j]=src[j+1]; } //修改后让src指向arr src=arr; } /** * 将指定位置的元素修改为指定的值 * * @param index * 要修改的元素的下标 * @param num * 修改之后的新值 */ public void modify(int index, E e) { src[index] = e; } /** * 在指定的位置插入指定的元素值 * * @param index * 要插入元素的位置 * @param e * 要插入的元素 */ public void insert(int index, E e) { //创建一个比src大1的数组 Object [] arr =new Object[src.length+1]; //拷贝添加的元素下标之前的元素 for(int i=0;i<index;i++){ arr[i]=src[i]; } //添加要插入的元素 arr[index]=e; //拷贝添加元素下标之后的元素 for(int j=index;j<arr.length;j++){ arr[j+1]=src[j]; } //让src重新指向arr src=arr; } /** * 得到容器中元素个数的方法 * * @return 返回容器中的元素个数 */ public int size() { //队列长度就是src数组的当前长度 int len = src.length; return len; } }
还有一个用来保存图形相关信息的一个类:
public class myshape { //定义形状的属性 private byte type; //保存坐标的属性 private int x1,y1,x2,y2; //设置颜色属性 private Color color; //设置形状的方法 public void setShape(byte type){ this.type=type; } //获取形状的方法 public byte getShape(){ return type; } //给坐标赋值的 方法 public void setvalue(int x1,int y1,int x2,int y2){ this.x1=x1; this.y1=y1; this.x2=x2; this.y2=y2; } //获取x1坐标值的方法 public int getx1(){ return x1; } //获取y1坐标值的方法 public int gety1(){ return y1; } //获取x2坐标值的方法 public int getx2(){ return x2; } //获取y2坐标值的方法 public int gety2(){ return y2; } //定义设置颜色的方法 public void setcolor(Color color){ this.color=color; } //定义获得颜色的方法 public Color getcolor() { return color; } }
重绘部分的代码
//在调用子类重写了的方法时,需要先调用父类中原有的方法??? public void paint(Graphics g) { super.paint(g);//调用父类中的方法 //把原来画的东西,自己写代码,再画出来! //获得队列对象 mylist mlis=drl.getMylist(); for(int i=0;i<mlis.size();i++){ //获得队列中的元素 Object ms=mlis.get(i); //强制转换为myshape类型 myshape sp=(myshape)ms; //画直线 if(sp.getShape()==1){ //设置颜色 hb.setColor(sp.getcolor()); hb.drawLine(sp.getx1(), sp.gety1(), sp.getx2(), sp.gety2()); } //画圆 if(sp.getShape()==2){ //设置颜色 hb.setColor(sp.getcolor()); hb.drawOval(sp.getx1(), sp.gety1(), sp.getx2(), sp.gety2()); } //画矩形 if(sp.getShape()==3){ //设置颜色 hb.setColor(sp.getcolor()); hb.drawRect(sp.getx1(), sp.gety1(), sp.getx2(), sp.gety2()); } // 话填充矩形 if(sp.getShape()==4){ //设置颜色 hb.setColor(sp.getcolor()); hb.fillRect(sp.getx1(), sp.gety1(), sp.getx2(), sp.gety2()); } //画填充圆 if(sp.getShape()==5){ //设置颜色 hb.setColor(sp.getcolor()); hb.fillOval(sp.getx1(), sp.gety1(), sp.getx2(), sp.gety2()); } } }
用这种方法进行重绘,十分严重的问题是当画的形状过多时,队列里面会保存大量的数据,而很多又是不需要的,所以我们得用另一种方法来重绘
2、用数组来保存数据 数组怎么用来保存图形的信息呢?
首先,让我们先了解一下计算机屏幕显示图像的原理。我们在 屏幕上看到的图像其实是有一个个像素点组成的,每个像素点可以显示不同的颜色,于是不同颜色 的像素点有机的组合在一起,便形成了丰富多彩的图像。根据这一点,想想如果我们能把屏幕上的 每个像素点的颜色信息保存起来,不就能把画图板上的图像信息保存了吗。而像素点的颜色值可以 用一个整数来表示,又画图板是一个矩形区域,所以用一个二维数组来保存是最合适的。
下面是保存画图板上每个像素点的颜色值的主要代码:
// 获取drawPanel左上角的相对于屏幕的位置 Point point = drjp.getLocationOnScreen(); // 获取drawPanel的大小 java.awt.Dimension dim = drjp.getPreferredSize(); // 创建一个要截取的区域对象(就是drawPanel所占据的区域) java.awt.Rectangle rect = new java.awt.Rectangle(point, dim); // 绘制完一个图像就截屏 BufferedImage img = robot.createScreenCapture(rect); // 根据图像创建二维数组 data = new int[img.getHeight()][img.getWidth()]; // 将图像上的每一个点的颜色存储到数组中 for (int i = 0; i < data.length; i++) { for (int j = 0; j < data[i].length; j++) { int rgb = img.getRGB(j, i); // 将坐标和下标对应保存颜色 data[i][j] = rgb; } }
相关推荐
图像处理课程上老师布置的作业,图像重绘最先由俄罗斯人由神经网络的方法得到,但也可以用频域来计算,结果仍需修正
基于MFC对话框程序,利用picture控件显示位图,并可实现图像重绘。内有代码与实现之详细步骤。 附带WORD说明,比较适合初学者入门
基于MFC对话框程序,利用picture控件显示位图,并可实现图像重绘。内有代码与实现之详细步骤。
通常在一般的图形程序在重绘时都有闪烁问题哦,这个解决图像重绘出现的闪烁问题,
C#复选框重绘 ,重写的Checkbox,支持选框大小调整、选框图像替换等,适合学习使用
这是一个重绘的 MFC List control 控件 ,里面包含了重绘的progress control控件、combo box控件 以及一个button 控件,可以在list control 控件的单元格中插入这些控件,便于更好的展示信息,对于初学者学习重绘...
做YUV播放器时在网上收集到的一些MFC+GDI图像显示的文档和例子。其中涉及窗口重绘时图像重绘的问题,还有图像显示的双缓冲技术等等!还是比较全面的!另外还有窗口尺寸发生改变,窗口控件的变化问题!
mfc重绘标题栏,更换标题栏背景图像,颜色,添加按钮,更换标题栏标题样式
具体原理是:先读取图像,然后进行图像重绘。相关的代码: Thread lakeThread; //图片倒影线程 Graphics graphics; //该Applet的Graphics对象 Graphics waveGraphics; //倒影的Graphics对象 Image image; //...
.net(winform) ProgressBar重绘美化,支持图像、单色、渐变色绘制样式,支持已加载值的动画刷,demo(vs2017)是一个简单测试工具,默认样式仿360下载安装时的进度条.
可以发现窗口内图像几乎看不到闪烁,而且窗口的元素已经保存下来重绘时任然可以看到图像。 如何使用: 进行项目开发时,可以先建立项目,然后把本解决方案框架拷贝到新建项目中即可。 也可以自己根据需要修改纯净...
c#下通过halcon实现3d点云重绘,即把图片的灰度信息作为Z坐标,Row作为Y坐标,Column作为X坐标重绘出来,用到访问内存方式实现,效率不错
用几何图形重绘图像,可以用圆形、三角形、矩形等几何图形重新绘制图像,并将结果导出为 SVG、PNG、JPG、GIF 等格式。
可以发现窗口内图像几乎看不到闪烁,而且窗口的元素已经保存下来重绘时任然可以看到图像。 如何使用: 进行项目开发时,可以先建立项目,然后把本解决方案框架拷贝到新建项目中即可。 也可以自己根据需要修改纯净...
可以发现窗口内图像几乎看不到闪烁,而且窗口的元素已经保存下来重绘时任然可以看到图像。 如何使用: 进行项目开发时,可以先建立项目,然后把本解决方案框架拷贝到新建项目中即可。 也可以自己根据需要修改纯净...
可以发现窗口内图像几乎看不到闪烁,而且窗口的元素已经保存下来重绘时任然可以看到图像。 如何使用: 进行项目开发时,可以先建立项目,然后把本解决方案框架拷贝到新建项目中即可。 也可以自己根据需要修改纯净...
包含图像重绘,迭代图像,递归图形等全功能的创意画板
2、手动重绘 原理: 利用内存设备的BitBlt()函数将初始CDC选入。将上面第⑤步的设备互换。 */ /* 程序过程: 1、绘制背景,在函数DrawSome()中实现;并将其放在OnPaint()函数中,保证每次刷新时依然存在; 2、...
Java生成倒影图片效果,这个图像的倒影效果看上去还是挺不错的,通过图像重绘的原理来实现,先读取图片,解析图像,然后重绘图片,生成倒影。
像坐标控制、旋转矩阵、定时器、生成图像、数据初始化、矩阵乘法、坐标旋转、判断是否是顺时针方向排列、鼠标按下、放开时的动作等,都可在本源码中得以体现。 Java编写的显示器显示模式检测程序 2个目标文件 内容...