• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C#教程 > C#双缓冲技术实例详解

C#双缓冲技术实例详解

作者:Alexander 字体:[增加 减小] 来源:互联网 时间:2017-05-28

Alexander 通过本文主要向大家介绍了马桶c的个人空间,c站,欲情 c max,维生素c,奔驰c200等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

本文实例分析了C#双缓冲技术。分享给大家供大家参考,具体如下:

双缓冲解决闪烁问题。

整理:

GDI+的双缓冲问题

一直以来的误区:.net1.1 和 .net 2.0 在处理控件双缓冲上是有区别的。
.net 1.1 中,使用:this.SetStyle(ControlStyles.DoubleBuffer, true);
.net 2.0中,使用:this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
导致画面闪烁的关键原因分析:

一、绘制窗口由于大小位置状态改变进行重绘操作时

绘图窗口内容或大小每改变一次,都要调用Paint事件进行重绘操作,该操作会使画面重新刷新一次以维持窗口正常显示。刷新过程中会导致所有图元重新绘制,而各个图元的重绘操作并不会导致Paint事件发生,因此窗口的每一次刷新只会调用Paint事件一次。窗口刷新一次的过程中,每一个图元的重绘都会立即显示到窗口,因此整个窗口中,只要是图元所在的位置,都在刷新,而刷新的时间是有差别的,闪烁现象自然会出现。

所以说,此时导致窗口闪烁现象的关键因素并不在于Paint事件调用的次数多少,而在于各个图元的重绘。

根据以上分析可知,当图元数目不多时,窗口刷新的位置也不多,窗口闪烁效果并不严重;当图元数目较多时,绘图窗口进行重绘的图元数量增加,绘图窗口每一次刷新都会导致较多的图元重新绘制,窗口的较多位置都在刷新,闪烁现象自然就会越来越严重。特别是图元比较大绘制时间比较长时,闪烁问题会更加严重,因为时间延迟会更长。

解决上述问题的关键在于:窗口刷新一次的过程中,让所有图元同时显示到窗口。

二、进行鼠标跟踪绘制操作或者对图元进行变形操作时

当进行鼠标跟踪绘制操作或者对图元进行变形操作时,Paint事件会频繁发生,这会使窗口的刷新次数大大增加。虽然窗口刷新一次的过程中所有图元同时显示到窗口,但也会有时间延迟,因为此时窗口刷新的时间间隔远小于图元每一次显示到窗口所用的时间。因此闪烁现象并不能完全消除!

所以说,此时导致窗口闪烁现象的关键因素在于Paint事件发生的次数多少。

解决此问题的关键在于:设置窗体或控件的几个关键属性。

使用双缓冲

解决双缓冲的关键技术:

1、设置显示图元控件的几个属性:  必须要设置,否则效果不是很明显!

this.SetStyle(ControlStyles.OptimizedDoubleBuffer | 
          ControlStyles.ResizeRedraw |
          ControlStyles.AllPaintingInWmPaint, true);
</div>

2、窗口刷新一次的过程中,让所有图元同时显示到窗口。

可以通过以下几种方式实现,这几种方式都涉及到Graphics对象的创建方式。

具体实现

1、利用默认双缓冲

(1)在应用程序中使用双缓冲的最简便的方法是使用 .NET Framework 为窗体和控件提供的默认双缓冲。通过将 DoubleBuffered 属性设置为 true。

this.DoubleBuffered=true;

</div>

(2)使用 SetStyle 方法可以为 Windows 窗体和所创作的 Windows 控件启用默认双缓冲。

SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

</div>

2、手工设置双缓冲

.netframework提供了一个类BufferedGraphicsContext负责单独分配和管理图形缓冲区。每个应用程序域都有自己的默认 BufferedGraphicsContext 实例来管理此应用程序的所有默认双缓冲。大多数情况下,每个应用程序只有一个应用程序域,所以每个应用程序通常只有一个默认 BufferedGraphicsContext。默认 BufferedGraphicsContext 实例由 BufferedGraphicsManager 类管理。通过管理BufferedGraphicsContext实现双缓冲的步骤如下:

(1)获得对 BufferedGraphicsContext 类的实例的引用。

(2)通过调用 BufferedGraphicsContext.Allocate 方法创建 BufferedGraphics 类的实例。

(3)通过设置 BufferedGraphics.Graphics 属性将图形绘制到图形缓冲区。

(4)当完成所有图形缓冲区中的绘制操作时,可调用 BufferedGraphics.Render 方法将缓冲区的内容呈现到与该缓冲区关联的绘图图面或者指定的绘图图面。

(5)完成呈现图形之后,对 BufferedGraphics 实例调用释放系统资源的 Dispose 方法。

完整的例子,在一个400*400的矩形框内绘制10000个随机生成的小圆。

BufferedGraphicsContext current = BufferedGraphicsManager.Current; //(1)
BufferedGraphics bg;
bg = current.Allocate(this.CreateGraphics(),this.DisplayRectangle); //(2)
Graphics g = bg.Graphics;//(3)
//随机 宽400 高400
System.Random rnd = new Random();
int x,y,w,h,r,i;
for (i = 0; i < 10000; i++)
{
    x = rnd.Next(400);
    y = rnd.Next(400);
    r = rnd.Next(20);
    w = rnd.Next(10);
    h = rnd.Next(10);
    g.DrawEllipse(Pens.Blue, x, y, w, h);
}
bg.Render();//(4)
//bg.Render(this.CreateGraphics());
bg.Dispose();//(5)

</div>

3、自己开辟一个缓冲区(如一个不显示的Bitmap对象),在其中绘制完成后,再一次性显示。

完整代码如下:

Bitmap bt = new Bitmap(400, 400);
Graphics bg = Graphics.FromImage(bt);
System.Random rnd = new Random();
int x, y, w, h, r, i;
for (i = 0; i < 10000; i++)
{
    x = rnd.Next(400);
    y = rnd.Next(400);
    r = rnd.Next(20);
    w = rnd.Next(10);
    h = rnd.Next(10);
    bg.DrawEllipse(Pens.Blue, x, y, w, h);
}
this.CreateGraphics().DrawImage(bt, new Point(0, 0)); 

</div>

另外一个例子,差不多

Graphics对象的创建方式:

a、在内存上创建一块和显示控件相同大小的画布,在这块画布上创建Graphics对象。

接着所有的图元都在这块画布上绘制,绘制完成以后再使用该画布覆盖显示控件的背景,从而达到“显示一次仅刷新一次”的效果!

实现代码(在OnPaint方法中):

Rectangle rect = e.ClipRectangle;
Bitmap bufferimage = new Bitmap(this.Width, this.Height);
Graphics g = Graphics.FromImage(bufferimage);
g.Clear(this.BackColor);
g.SmoothingMode = SmoothingMode.HighQuality; //高质量
g.PixelOffsetMode = PixelOffsetMode.HighQuality; //高像素偏移质量
foreach (IShape drawobject in doc.drawObjectList)
{
    if (rect.IntersectsWith(drawobject.Rect))
    {
      drawobject.Draw(g);
      if (drawobject.TrackerState == config.Module.Core.TrackerState.Selected
        && this.CurrentOperator == Enum.Operator.Transfrom)//仅当编辑节点操作时显示图元热点
      {
        drawobject.DrawTracker(g);
      }
    }
}
using (Graphics tg = e.Graphics)
{
    tg.DrawImage(bufferimage, 0, 0);//把画布贴到画面上
}

</div>

b、直接在内存上创建Graphics对象:

Rectangle rect = e.ClipRectangle;
BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current;
BufferedGraphics myBuffer = currentContext.Allocate(e.Graphics, e.ClipRectangle);
Graphics g = myBuffer.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
g.Clear(this.BackColor);
foreach (IShape drawobject in doc.drawObjectList)
{
    if (rect.IntersectsWith(drawobject.Rect))
    {
      drawobject.Draw(g);
      if (drawobject.TrackerState == config.Module.Core.TrackerState.Selected
        && this.CurrentOperator == Enum.Operator.Transfrom)//仅当编辑节点操作时显示图元热点
      {
        drawobject.DrawTracker(g);
      }
    }
}
myBuffer.Render(e.Graphics);
g.Dispose();
myBuffer.Dispose();//释放资源

</div>

至此,双缓冲问题解决,两种方式的实现效果都一样,但最后一种方式的占有的内存很少,不会出现内存泄露!

接下来是对acdsee拖动图片效果的实现。开始不懂双缓冲,以为双缓冲可以解决这个问题,结果发现使用了双缓冲没啥效果,请教了高人,然后修改了些代码,完成这个效果。

图片是在pictureBox1里。

Bitmap currentMap;
bool first = true;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
  if (zoom == 0)
  {
    if (e.Button == MouseButtons.Left) //dragging
      mousedrag = e.Location;
    Image myImage = myMap.GetMap();
    currentMap = new Bitmap(myImage);
    first = false;
  }
}
private void pictureBox1_MouseMove(o



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C#利用ReportViewer生成报表
  • C#基于正则去掉注释的方法示例
  • C#中new的用法及与override的区别分析
  • C#实现两个richtextbox控件滚动条同步滚动的简单方法
  • C# for循环的经典案例集锦
  • C#操作word的方法示例
  • C#使用WebClient登录网站并抓取登录后的网页信息实现方法
  • C# WinForm制作异形窗体与控件的方法
  • C#实现Excel表数据导入Sql Server数据库中的方法
  • C#使用NPOI上传excel

相关文章

  • 2017-05-28C#使用windows服务开启应用程序的方法
  • 2017-05-28C#无限参数的写法
  • 2017-05-28利用C#实现分布式数据库查询
  • 2017-05-28C#实现矩阵乘法实例分析
  • 2017-05-28C#通过windows注册表获取软件清单的方法
  • 2017-05-28C#实现开机自动启动设置代码分享
  • 2017-05-28C#中float的取值范围和精度分析
  • 2017-05-28C# 复制指定节点的所有子孙节点到新建的节点下
  • 2017-05-28C#获取文件相关信息的方法
  • 2017-05-28深入理解C#中new、override、virtual关键字的区别

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 深入多线程之:双向信号与竞赛的用法分析
    • 浅谈C#设计模式之工厂模式
    • C#实现一键换IP、重置DNS、网关及掩码的方法
    • C#使用Ado.Net更新和添加数据到Excel表格的方法
    • C#基于COM方式读取Excel表格的方法
    • 基于Silverlight打印的使用详解,是否为微软的Bug问题
    • c#利用webmail邮件系统发送邮件示例分享
    • C# 创建、部署和调用WebService简单示例
    • C#利用com操作excel释放进程的解决方法
    • C#调用VB进行简繁转换的方法

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有