版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、的双缓冲问题 我想有很多搞图形方面的朋友都会用到双缓冲技术的时候,而且有的时候她的确是个头疼的问题。最近我也要用双缓冲技术,程序怎么 调试都不合适,当要对图形进行移动时,总是会出现闪烁抖动。在网上找了些资料,说得都不清不楚的,折腾了一晚上也没弄出来。第二 天觉定自己研究一下。现在把自己的一些想法拿出来跟大家分享一下。 双缓冲的基本原理:(转) 一直以来的误区:.netl.1和.net 2.0在处理控件双缓冲上是有区别的。 .net 1.1 中,使用:this.SetStyle(ControlStyles.DoubleBuffer, true); .net 2.0 中,使用:this.SetSt
2、yle(ControlStyles.OptimizedDoubleBuffer, true); 怪不说老是提示参数无效,一直也不知道是这个问题,呵呵 要知道,图元无闪烁的实现和图元的绘制方法没有多少关系,只是绘制方法可以控制图元的刷新区域,使双缓冲性能更优! 导致画面闪烁的关键原因分析: 一、绘制窗口由于大小位置状态改变进行重绘操作时 绘图窗口内容或大小每改变一次,都要调用Paint事件进行重绘操作,该操作会使画面重新刷新一次以维持窗口正常显示。刷新过程中 会导致所有图元重新绘制,而各个图元的重绘操作并不会导致Paint事件发生,因此窗口的每一次刷新只会调用Paint事件一次。窗口刷新 一次的
3、过程中,每一个图元的重绘都会立即显示到窗口,因此整个窗口中,只要是图元所在的位置,都在刷新,而刷新的时间是有差别的, 闪烁现象自然会出现。所以说,此时导致窗口闪烁现象的关键因素并不在于Paint事件调用的次数多少,而在于各个图元的重绘。 根据以上分析可知,当图元数目不多时,窗口刷新的位置也不多,窗口闪烁效果并不严重;当图元数目较多时,绘图窗口进行重绘的图 元数量增加,绘图窗口每一次刷新都会导致较多的图元重新绘制,窗口的较多位置都在刷新,闪烁现象自然就会越来越严重。特别是图元 比较大绘制时间比较长时,闪烁问题会更加严重,因为时间延迟会更长。 解决上述问题的关键在于:窗口刷新一次的过程中,让所有图
4、元同时显示到窗口。 二、进行鼠标跟踪绘制操作或者对图元进行变形操作时 当进行鼠标跟踪绘制操作或者对图元进行变形操作时,Paint事件会频繁发生,这会使窗口的刷新次数大大增加。虽然窗口刷新一次的 过程中所有图元同时显示到窗口,但也会有时间延迟,因为此时窗口刷新的时间间隔远小于图元每一次显示到窗口所用的时间。因此闪烁 现象并不能完全消除!所以说,此时导致窗口闪烁现象的关键因素在于Paint事件发生的次数多少。 解决此问题的关键在于:设置窗体或控件的几个关键属性。 下面讲具体的实现方法:(转) 1、在内存中建立一块虚拟画布” Bitmap bmp = new Bitmap(600, 600); 2、
5、 获取这块内存画布的Graphics 引用:Graphics g = Graphics.FromImage(bmp); 3、在这块内存画布上绘图:如画线 g.DrawLine(添加参数); 4、 将内存画布画到窗口中:this.CreateGraphics().DrawImage(bmp, 0, 0); 在构造函数中加如下代码 代码一: SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); /禁止擦除背景. SetStyle(ControlStyles.Doubl
6、eBuffer, true); / 双缓冲 或代码二: this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); this.UpdateStylesO; (转载结束) 上述方式适合直接在窗体上绘制图形,并且很容易做到。但有时我们需要在某个控件上绘制图形,那该怎么办呢?原理跟直接在窗体上 绘制图形采用双缓冲是一样的,也要在控件的构造函数里设置上述代码一或代码二。那么又怎么设置呢?我是通过阅读MSDN,找到自定 义控件的方法,并在控件
7、的构造函数里设置。在后面的附录里,我会说明怎么做。 在Microsoft Visual Studio 2005环境下的,用的C#语言,并采用 GDI+。目标是实现简单的鼠标拖动画线,并且要把之前画过的线都重新 画出来。 整个程序使用了三个控件:一个 Splitcontainer控件、一个自定义的 Panel控件和一个 VS自带的Panel控件。Splitcontainer控件的大小 设置成窗体宽、半窗体高并定位在窗体的下半部分。自定义的Panel控件和VS自带的Panel控件都是通过设置它们的 Dock属性使它们绑 定到SplitContainer控件的Panel1和Panel2上。附录中会说
8、到自定义的 Panel控件是怎么定义的。 窗体的上半部分采用双缓冲。自定义的Panel控件采用了双缓冲,是通过在自定义Panel控件时设置样式来做到的(设置方法与窗体的双 缓冲设置方法一样,如下面三条语句),这不能够在面板的Paint方法里直接设置,因为SetStyleO在Panel类中不是public方法。VS自带 的Panel控件没有采用双缓冲。 SetStyle(ControlStyles.AllPaintinglnWmPaint, true); SetStyle(ControlStyles.UserPaint, true); SetStyle(C on trolStyles.Optim
9、izedDoubleBuffer, true); 我把三者结合在一块,我想你一定能够弄明白双缓冲的原理、实现以及效果了吧,如图。如果朋友你不是很清楚,可以给我留言,咱们 L 一一一- Fs Sr F i C 1 有两种方式来创建 Graphics对象:第一是在内存上创建一块和显示区域或控件相同大小的画布,在这块画布上创建Graphics对象。接着 所有的图元都在这块画布上绘制,绘制完成以后再使用该画布覆盖显示控件的背景,从而达到显示一次仅刷新一次”的效果!第二是直接 在内存上创建Graphics对象。 第一种方式具体代码如下: using System; using System.Collec
10、ti on s.Ge neric; using System.Comp onen tModel; using System.Data; using System.Draw ing; using System.Text; using System.Wi ndows.Forms; using System.Draw in g.Draw in g2D; n amespace Pan elLib2Test public partial class Form1 : Form public Form1() In itializeComp onen t(); /激活窗体的双缓冲技术,可以注释掉看看是什么效果
11、 SetStyle(ControlStyles.AIIPaintinglnWmPaint, true); SetStyle(ControlStyles.UserPaint, true); SetStyle(C on trolStyles.OptimizedDoubleBuffer, true); private Point startP, endP, curP = new Point();定义线段的起始点,终止点,鼠标当前位置 /用在自定义面板上的变量,采用双缓冲 private bool mdFlag = false;/ 标志左键是否按下 private Poi nt叩 li nes = n
12、ew Poi nt1OOO; 存储已经画过的线段 private int k = 0;/线段数组当前下标,表示已经画过的线段数 /用在系统面板上的变量,不采用双缓冲 private bool mdFlag2 = false; private Poi nt li nes2 = new Poi nt1OOO; private int k2 = 0; /用在自定义面板上的变量,采用双缓冲 private bool mdFlag3 = false; private Poi nt叩 li nes3 = new Poi nt1OOO; private int k3 = 0; private void Fo
13、rm1_Load(object sen der, Even tArgs e) /初始化各线段数组 for (int i = 0; i 1000; i+) lin esi = new Poi nt2; for (int i = 0; i 1000; i+) lin es2i = new Poi nt2; for (int i = 0; i 1000; i+) lin es3i = new Poi nt2; 将分割控件定位在窗体的下半部分 splitContainerl.Location = new Point(0, ClientSize.Height / 2); splitCo ntai ner
14、1.Size = new Size(Clie ntSize.Width, Clie ntSize.Height / 2); private void pan elLib21_Pai nt(object sen der, Pain tEve ntArgs e) Graphics g = e.Graphics; /Graphics g = panelLib21.CreateGraphics();用这个不行,可以试试是什么效果 Bitmap bmp = new Bitmap(panelLib21.Width, panelLib21.Height); Graphics bufg = Graphics
15、.Fromlmage(bmp); g.Clear(panelLib21.BackColor); 可用可不用,视具体情况 bufg.Clear(panelLib21.BackColor); 可用可不用 bufg.DrawLine(new Pen(Color.Black, 1), startP, endP); for (i nt i = 0; i = k; i+) bufg.DrawLi ne(new Pe n(Color.Black, 1), li nesi0, li nesi1); bufg.DrawStri ng(Custom Pa nel DoubleBufferd, new Fon t(
16、verda na, 16), new SolidBrush(Color.Red), 0, 0); g.DrawImage(bmp, 0, 0); bufg.Dispose(); bmp.Dispose(); /g.DisposeO;/注意这个地方的绘图面g是窗体的Paint事件中的,不能被释放,否则出现 Application.Run(new Form1();参数无效错误 private void pan elLib21_MouseDow n(o bject sen der, MouseEve ntArgs e) if (e.Button = MouseButt on s.Left) star
17、tP = e.Locati on; endP = e.Locati on; mdFlag = true; panelLib21.Capture = true;/ 捕获 panelLib21 上鼠标按下 private void pan elLib21_MouseMove(object sen der, MouseEve ntArgs e) curP = e.Locati on; if (mdFlag) if (en dP.X != curP.X | en dP.Y != curP.Y) endP = curP; panelLib21.lnvalidate(); 刷新 panelLib21 pr
18、ivate void pan elLib21_MouseUp(object sen der, MouseEve ntArgs e) lin esk0 = startP; lin esk1 = en dP; k+; mdFlag = false; panelLib21.Capture = false;/ 释放 panelLib21 上鼠标按下 private void pan el1_Pa in t(object sen der, Pain tEve ntArgs e) Graphics g = e.Graphics; / Graphics g = this.CreateGraphics();
19、Bitmap bmp = new Bitmap(panelLib21.Width, panelLib21.Height); Graphics bufg = Graphics.Fromlmage(bmp); g.Clear(this.BackColor);可用可不用,视具体情况 bufg.Clear(this.BackColor); 可用可不用 bufg.DrawLine(new Pen(Color.Black, 1), startP, endP); for (int i = 0; i = k2; i+) bufg.DrawLi ne(new Pe n(Color.Black, 1), li n
20、es2i0, li nes2i1); bufg.DrawStri ng(System Panel Un-DoubleBufferd, new Fon t(verda na, 16), new SolidBrush(Color.Red), 0, 0); g.Drawlmage(bmp, 0, 0); bufg.Dispose(); bmp.Dispose(); private void pan el1_MouseDow n(o bject sen der, MouseEve ntArgs e) if (e.Button = MouseButt on s.Left) startP = e.Loca
21、ti on; endP = e.Locati on; mdFlag2 = true; pan el1.Capture = true; private void panel1_MouseMove(object sender, MouseEventArgs e) curP = e.Locati on; if (mdFlag2) if (en dP.X != curP.X | en dP.Y != curP.Y) endP = curP; pan el1n validate。; private void panel1_MouseUp(object sender, MouseEventArgs e)
22、lin es2k20 = startP; lin es2k21 = endP; k2+; mdFlag2 = false; pan el1.Capture = false; private void Form1_Pa in t(object sen der, Pain tEve ntArgs e) Graphics g = e.Graphics; / Graphics g = this.CreateGraphics(); Bitmap bmp = new Bitmap(Clie ntSize .Width, Clie ntSize .Height - splitCo ntai ner1 .He
23、ight );/定义窗体宽、半窗体高的缓冲位图 Graphics bufg = Graphics.Fromlmage(bmp); g.Clear(this.BackColor);可用可不用,视具体情况 bufg.Clear(this.BackColor); 可用可不用 bufg.DrawLine(new Pen(Color.Black, 1), startP, endP); for (int i = 0; i = k3; i+) bufg.DrawLi ne(new Pe n(Color.Black, 1), li nes3i0, li nes3i1); bufg.DrawStri ng(Fr
24、om DoubleBufferd, new Fo nt(verda na, 16), new SolidBrush (Color.Red), 0, 0); g.DrawImage(bmp, 0, 0); bufg.Dispose(); bmp.Dispose(); private void Form1_MouseDow n(o bject sen der, MouseEve ntArgs e) if (e.Button = MouseButt on s.Left) startP = e.Locati on; endP = e.Locati on; mdFlag3 = true; Capture
25、 = true; private void Form1_MouseMove(object sender, MouseEventArgs e) curP = e.Locati on; if (mdFlag3) if (en dP.X != curP.X | en dP.Y != curP.Y) endP = curP; Invalidate(new Rectangle(0, 0, ClientSize.Width, ClientSize.Height - splitContainer1.Height);只刷新窗体的上半部分 private void Form1_MouseUp(object se
26、n der, MouseEve ntArgs e) lin es3k30 = startP; lin es3k31 = en dP; k3+; mdFlag3 = false; Capture = false; private void Form1_SizeCha nged(object sen der, Even tArgs e) splitContainer1.Location = new Point(0, ClientSize.Height / 2); splitContainer1.Size = new Size(ClientSize.Width, ClientSize.Height
27、/ 2); 第二种方式只需将Form1_Paint方法里改成如下代码: private void Form1_Paint(object sender, PaintEventArgs e) BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current; BufferedGraphics bufg = currentContext .Allocate (e.Graphics, new Rectangle(0, 0, Clie ntSize.Width, Clie ntSize.Height - splitCo nt
28、ai nerl.Height); Graphics g = bufg.Graphics; g.Clear(this.BackColor); g.DrawLi ne(new Pe n(Color.Black, 1), startP, en dP); for (int i = 0; i = k3; i+) g.DrawLine(new Pen(Color.Black, 1), lines3i0, lines3i1); g.DrawStri ng(From DoubleBufferd, new Fo nt(verda na, 16), new SolidBrush (Color.Red), 0, 0
29、); bufg.Re nder(e.Graphics); g.Dispose(); bufg .Dispose (); 你可以在panel1_Paint方法中设置如下代码来证明SetStyle的那三句话的重要性: private void pan el1_Pa in t(object sen der, Pain tEve ntArgs e) BufferedGraphicsC on text curre ntCon text = BufferedGraphicsMa nager.Curre nt; BufferedGraphics bufg = curre ntCon text.Allocat
30、e(e.Graphics, new Recta ngle(0, 0, pan el1.Width, pan el1.Height); Graphics g = bufg.Graphics; g.Clear(pa nel1.BackColor); g.DrawLi ne(new Pe n(Color.Black, 1), startP, en dP); for (int i = 0; i = k2; i+) g.DrawLine(new Pen(Color.Black, 1), lines2i0, lines2i1); g.DrawStri ng(System Pa nel Un-DoubleB
31、ufferd, new Fo nt(verda na, 16), new SolidBrush(Color.Red), 0, 0); bufg.Re nder(e.Graphics); g.Dispose(); bufg.Dispose(); 附录:自定义设置双缓冲的Panel面板控件 1. 创建项目 创建新项目时,应指定其名称以便设置根命名空间、程序集名称和项目名称,并确保默认组件位于正确的命名空间中。 创建panelLib2控件库和panelLib2控件在 文件”菜单上,指向 新建”然后单击 项目”打开 新建项目”对话框 在Visual C#项目列表中,选择“Windows控件库项目模板,
32、然后在名称框中键入 panelLib2 在解决方案资源管理器中右击“ UserControl1.cs,再从快捷菜单中选择重命名”将文件名更改为panelLib2.cs。系统询问是否要重命 名对“UserControll代码元素的所有引用时,单击是按钮。 在解决方案资源管理器”中右击“ panelLib2.cs,再选择 查看代码” 找到class语句行public partial class panelLib2,并将此控件继承的类型从UserControl更改为Panel。这允许您所继承的控件继承Pane 控件的所有功能。 在 解决方案资源管理器中打开“ panelLib2.cs节点,以显示设计器生成的代码文件“panelLib2.Designer.cs。在代码编辑器中打开此文 件。 找到InitializeComponent方法并删除分配AutoScaleMode属性的行。在 Panel控件中并不存在此属性。 从 文件”菜单中,选择 全部保存”来保存项目。 注意 可视化
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 出租车收费协议合同书
- 公司采购空调合同范本
- 位临时工保安合同协议
- 农村旧房拆除合同范本
- 出租沿街房转让协议书
- 动画模板制作合同协议
- 农村承包水池合同范本
- 动画设计制作合同范本
- 2025年人体解剖联考试题及答案
- 劳务平行发包合同范本
- 西安鸡蛋行业现状分析
- 柜子安装服务流程
- patran培训教材(有限元分析)
- 汽车设计-汽车 仪表板横梁设计规范模板
- 危急值的报告制度与流程
- 腾讯云大数据云平台TBDS 产品白皮书
- 《创新思维》考试复习题库(含答案)
- 口腔种植学 课件 口腔种植学导论-课件
- 2021年投资学考研真题(含复试)与典型题详解
- 非谓语动词在写作上的应用 课件 【知识导航+拓展迁移】高三英语一轮复习
- GB/T 1864-2012颜料和体质颜料通用试验方法颜料颜色的比较
评论
0/150
提交评论