问题描述
主要是在一个Panel上面放了一个继承Control的控件,Dock模式为Fill,主要的绘图区域为Control。.net版本为2.0,winform的程序。在进行放大和缩小的时候出现了闪烁的现象,具体原因可能为paint2次绘制导致。其中放大部分代码为:publicvoidDrawZoomIn(){scale=scale/ampfactor;Pointpt=GetDisplayCenter();//获取当前显示中心intiwidth=(int)(Width/ampfactor);//ampfactor是放大系数intiheight=(int)(Height/ampfactor);//对长和宽进行长度限制if(iwidth>7000||iheight>7000){scale=scale*ampfactor;return;}this.Size=newSize(iwidth,iheight);//对滚动条进行控制if(iwidth>=rcclient.Width){pt.X=(int)(pt.X/ampfactor-rcclient.Width/2);pt.Y=(int)(pt.Y/ampfactor-rcclient.Height/2);owner.AutoScrollPosition=pt;//owner为control的容器panelpanel的autoscroll属性为true}}
在paint部分的代码为privatevoidDrawArea_Paint(objectsender,PaintEventArgse){if(e.ClipRectangle.Width==0||e.ClipRectangle.Height==0){return;}DrawGrid(e.Graphics);//绘制网格_graphicsList.Draw(e.Graphics,scale,ClientRectangle);//绘制保存的矩形、线等}
其中Panel和Control里面都设置了双缓冲,双缓冲代码为(panel自己写了一个继承panel的类)this.SetStyle(ControlStyles.OptimizedDoubleBuffer|ControlStyles.ResizeRedraw|ControlStyles.Selectable|ControlStyles.AllPaintingInWmPaint|ControlStyles.UserPaint|ControlStyles.SupportsTransparentBackColor,true);this.UpdateStyles();
解决方案
解决方案二:
那个WinForm重绘。好像官方的说法是:只绘制无效的区域,而不要全部区域都绘制。当然:绘制线段,颜色应该不损耗效率——但是,绘制图片往往很卡。GDI绘图,有点卡——再所难免。
解决方案三:
引用1楼sxl514286339的回复:
那个WinForm重绘。好像官方的说法是:只绘制无效的区域,而不要全部区域都绘制。当然:绘制线段,颜色应该不损耗效率——但是,绘制图片往往很卡。GDI绘图,有点卡——再所难免。
因为放大后,我调整了显示区域,所以我就全部进行了绘制。关于绘制图片部分,其实就是一些多线段而已,并且多线段并不复杂的。100条线都没有到。
解决方案四:
莫非楼主电脑很卡?
解决方案五:
或者,楼主试试:你要使用DrawArea控件的Paint事件。而是DrawArea自身继承Control的OnPaint方法。
解决方案六:
引用4楼sxl514286339的回复:
或者,楼主试试:你要使用DrawArea控件的Paint事件。而是DrawArea自身继承Control的OnPaint方法。
不是很明白,这句话啥意思。
解决方案七:
引用4楼sxl514286339的回复:
或者,楼主试试:你要使用DrawArea控件的Paint事件。而是DrawArea自身继承Control的OnPaint方法。
电脑绝对不卡,用的都是最新的CPU和硬件的。
解决方案八:
publicclassMyControl:Control{protectoverridevoidOnPaint(Event??Arge){base.OnPaint();e.Grap**.Draw(Image.ImageFrom("D:AAAA.png"));}}——然后看这个控件卡补卡。
解决方案:
1.检查下是否存在循环事件(绘图过程中触发绘图事件)2.检查下单次绘图耗时
解决方案:
引用6楼kwfly的回复:
Quote: 引用4楼sxl514286339的回复:
或者,楼主试试:你要使用DrawArea控件的Paint事件。而是DrawArea自身继承Control的OnPaint方法。电脑绝对不卡,用的都是最新的CPU和硬件的。
跟显卡有关系,不是说CPU配置高就无敌了
解决方案:
1.在DrawArea里面设置双缓冲。2.双缓冲原理是先绘制到一个Bitmap上,再将Bitmap拷贝到DrawImage到控件上。(惭愧,我没深究过第1点处设置了双缓冲后这里是不是就可以直接使用Graphics绘图)3.如果使用双缓冲并且是在OnPaint上面绘图,之后还会有闪烁的问题,那你就得看看OnPaint里面做了太多/久/耗性能的事情。总之:你在OnPaint中先绘到一个与控件一样大小的Bitmap上,绘制完成再将Bitmap拷贝(DrawImage)上控件。
解决方案:
引用10楼Yokeqi的回复:
1.在DrawArea里面设置双缓冲。2.双缓冲原理是先绘制到一个Bitmap上,再将Bitmap拷贝到DrawImage到控件上。(惭愧,我没深究过第1点处设置了双缓冲后这里是不是就可以直接使用Graphics绘图)3.如果使用双缓冲并且是在OnPaint上面绘图,之后还会有闪烁的问题,那你就得看看OnPaint里面做了太多/久/耗性能的事情。总之:你在OnPaint中先绘到一个与控件一样大小的Bitmap上,绘制完成再将Bitmap拷贝(DrawImage)上控件。
双缓冲原理还是清楚的,在MFC里面都是采用你说的方法做的,突然换到C#里面有自己提供的缓冲所以就没有进行处理。刚测试了一下,OnPaint里面如果完成绘图一次的操作大概需要15ms。里面画网格部分没有优化,全部采用所有线全部画一遍。
解决方案:
引用8楼assky124的回复:
1.检查下是否存在循环事件(绘图过程中触发绘图事件)2.检查下单次绘图耗时
单次绘图耗时为15ms左右。绘图操作确实执行了两次,但是不存在循环绘图的情况。一个是调整Panel的Scroll位置的时候进行了绘制。一个是调整继承自Control也就是绘图控件的大小的时候产生了重绘的操作。
解决方案:
引用11楼kwfly的回复:
Quote: 引用10楼Yokeqi的回复:
1.在DrawArea里面设置双缓冲。2.双缓冲原理是先绘制到一个Bitmap上,再将Bitmap拷贝到DrawImage到控件上。(惭愧,我没深究过第1点处设置了双缓冲后这里是不是就可以直接使用Graphics绘图)3.如果使用双缓冲并且是在OnPaint上面绘图,之后还会有闪烁的问题,那你就得看看OnPaint里面做了太多/久/耗性能的事情。总之:你在OnPaint中先绘到一个与控件一样大小的Bitmap上,绘制完成再将Bitmap拷贝(DrawImage)上控件。双缓冲原理还是清楚的,在MFC里面都是采用你说的方法做的,突然换到C#里面有自己提供的缓冲所以就没有进行处理。刚测试了一下,OnPaint里面如果完成绘图一次的操作大概需要15ms。里面画网格部分没有优化,全部采用所有线全部画一遍。
也可能,不是你重绘的问题,而是Form在画Panel的时候产生的闪烁。C#有个很不爽的地方是Form上的控件一多显示的时候就会闪烁。所以你可以首先试试把你这个重绘的做法单独做在一个Form上,然后用弹出框的方式弹出来看看是否会闪烁,如果不会那基本就能确定是因为那个Panel什么的问题而不是你这些重绘代码的问题了。相应的解决方案相信你也就有了。
解决方案:
开双缓存。
解决方案:
引用13楼Yokeqi的回复:
Quote: 引用11楼kwfly的回复:
Quote: 引用10楼Yokeqi的回复:
1.在DrawArea里面设置双缓冲。2.双缓冲原理是先绘制到一个Bitmap上,再将Bitmap拷贝到DrawImage到控件上。(惭愧,我没深究过第1点处设置了双缓冲后这里是不是就可以直接使用Graphics绘图)3.如果使用双缓冲并且是在OnPaint上面绘图,之后还会有闪烁的问题,那你就得看看OnPaint里面做了太多/久/耗性能的事情。总之:你在OnPaint中先绘到一个与控件一样大小的Bitmap上,绘制完成再将Bitmap拷贝(DrawImage)上控件。双缓冲原理还是清楚的,在MFC里面都是采用你说的方法做的,突然换到C#里面有自己提供的缓冲所以就没有进行处理。刚测试了一下,OnPaint里面如果完成绘图一次的操作大概需要15ms。里面画网格部分没有优化,全部采用所有线全部画一遍。
也可能,不是你重绘的问题,而是Form在画Panel的时候产生的闪烁。C#有个很不爽的地方是Form上的控件一多显示的时候就会闪烁。所以你可以首先试试把你这个重绘的做法单独做在一个Form上,然后用弹出框的方式弹出来看看是否会闪烁,如果不会那基本就能确定是因为那个Panel什么的问题而不是你这些重绘代码的问题了。相应的解决方案相信你也就有了。
感谢帮忙分析。目前测试情况为,将owner.AutoScrollPosition=pt;//owner为control的容器panelpanel的autoscroll属性为true上面这句话去掉之后就看不到闪烁的情况了。但是panel的滚动条都变为了0位置,不是我想要的居中效果。
解决方案:
引用15楼kwfly的回复:
Quote: 引用13楼Yokeqi的回复:
Quote: 引用11楼kwfly的回复:
Quote: 引用10楼Yokeqi的回复:
1.在DrawArea里面设置双缓冲。2.双缓冲原理是先绘制到一个Bitmap上,再将Bitmap拷贝到DrawImage到控件上。(惭愧,我没深究过第1点处设置了双缓冲后这里是不是就可以直接使用Graphics绘图)3.如果使用双缓冲并且是在OnPaint上面绘图,之后还会有闪烁的问题,那你就得看看OnPaint里面做了太多/久/耗性能的事情。总之:你在OnPaint中先绘到一个与控件一样大小的Bitmap上,绘制完成再将Bitmap拷贝(DrawImage)上控件。双缓冲原理还是清楚的,在MFC里面都是采用你说的方法做的,突然换到C#里面有自己提供的缓冲所以就没有进行处理。刚测试了一下,OnPaint里面如果完成绘图一次的操作大概需要15ms。里面画网格部分没有优化,全部采用所有线全部画一遍。
也可能,不是你重绘的问题,而是Form在画Panel的时候产生的闪烁。C#有个很不爽的地方是Form上的控件一多显示的时候就会闪烁。所以你可以首先试试把你这个重绘的做法单独做在一个Form上,然后用弹出框的方式弹出来看看是否会闪烁,如果不会那基本就能确定是因为那个Panel什么的问题而不是你这些重绘代码的问题了。相应的解决方案相信你也就有了。
感谢帮忙分析。目前测试情况为,将owner.AutoScrollPosition=pt;//owner为control的容器panelpanel的autoscroll属性为true上面这句话去掉之后就看不到闪烁的情况了。但是panel的滚动条都变为了0位置,不是我想要的居中效果。
嘿嘿,感觉有点奇怪,偷懒吧你。你重绘所有区域(会超出Panel的区域),然后利用Panel的AutoScrollPosition来调整显示区域。看起来确实蛮方便。正常来说应该确定好显示区域,然后重绘这个区域到Panel就是,不要再把调整丢给控件去做。
解决方案:
15ms是不会卡的。至少你感觉不到。除非你是不停的绘制。人的眼镜所所接受的一秒钟24帧。并不多40ms一帧。