C#-gdi画图,双缓冲画图,Paint事件的触发---ShinePans

在使用gdi技术画图时,有时会发现图形线条不够流畅,或者在改变窗口大小时会闪烁不断的现象.(Use DoubleBuffer to solve it!)

                                                                                                                                                                         
                                                           

1.线条不流畅:窗口在重绘时自身重绘与图形重绘之间存在时间差,导致二者图像显示不协调

2.改变窗口大小不流畅:重绘时自身背景颜色与图形颜色频繁交替,造成视觉上的闪烁

以下,用四个图形样例解决问题 :贝塞尔曲线,圆形,矩形,不规则图形

思路:首先用Bitmap类的构造方法创建一个位图实例,然后通过调用Graphics类的FromImage方法创建画布对象,最后调用Grapgics类的DrawImage方法来实如今窗口上绘制图形.

public Bitmap(int width,int height); //width 定义位图的宽度  height 定义位图的高度

Bitmap lacalBitmap =new Bitmap(CilentRectangle.Width,CilentRectangle.Height); //创建一个与窗口工作区大小同样的位图实例

public static Graphics FromImage(Image image);// image:Image类的子类的实例引用

Bitmap localBitmap=new Bitmap(CilentRectangle.Width,CilentRectangle.Height) //创建位图实例

public void DrawImage(Image image,int x,int y);    // image:要绘制的图像  x:绘制的图像的左上角 x坐标 y:左上角y坐标

Graphics g=e.Graphics;//获取窗口画布

g.DrawImage(localBitmap,0,0);  //在窗口中绘制出内存中的图像

实现:因为Paint被 .net隐藏,我们须要在窗口代码中加上自己的Paint事件中绘制窗口

this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);

private void InitializeComponent()

{

this.SuspendLayout();

//

// Form1

//

this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);

this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

this.ClientSize = new System.Drawing.Size(388, 325);

this.MaximizeBox = false;

this.MinimizeBox = false;

this.Name = "Form1";

this.Text = "双缓冲技术画图";

this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);

this.ResumeLayout(false);

}

this.Paint+=new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);

源码:

Form1.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace DoubleBuffer
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Bitmap localBitmap = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);
            //创建位图实例
            Graphics bitmapGraphics = Graphics.FromImage(localBitmap);
            bitmapGraphics.Clear(BackColor);
            bitmapGraphics.SmoothingMode = SmoothingMode.AntiAlias;
            PaintImage(bitmapGraphics);
            Graphics g = e.Graphics;//获取窗口画布
            g.DrawImage(localBitmap, 0, 0); //在窗口的画布中绘画出内存中的图像
            bitmapGraphics.Dispose();
            localBitmap.Dispose();
            g.Dispose();
        }
        private void PaintImage(Graphics g)
        {
            //画图
            GraphicsPath path = new GraphicsPath(new Point[]{ new Point(100,60),new Point(350,200),new Point(105,225),new Point(190,ClientRectangle.Bottom),
                new Point(50,ClientRectangle.Bottom),new Point(50,180)}, new byte[]{
                    (byte)PathPointType.Start,
                    (byte)PathPointType.Bezier,
                    (byte)PathPointType.Bezier,
                    (byte)PathPointType.Bezier,
                    (byte)PathPointType.Line,
                    (byte)PathPointType.Line});
            PathGradientBrush pgb = new PathGradientBrush(path);
            pgb.SurroundColors = new Color[] { Color.Green, Color.Yellow, Color.Red, Color.Blue, Color.Orange, Color.LightBlue };
            g.FillPath(pgb, path);
            g.DrawString("双缓冲画图", new Font("宋体", 18, FontStyle.Bold), new SolidBrush(Color.Red), new PointF(110, 20));
            g.DrawBeziers(new Pen(new SolidBrush(Color.Green),2),new Point[] {new Point(120,100),new Point(120,120),new Point(120,100),new Point(120,150)});
            g.DrawArc(new Pen(new SolidBrush(Color.Blue), 5), new Rectangle(new Point(120, 170), new Size(60, 60)), 0, 360);
            g.DrawRectangle(new Pen(new SolidBrush(Color.Orange), 3), new Rectangle(new Point(240, 260), new Size(90, 50)));
        }

    }
}

Form1设计:

namespace DoubleBuffer
{
    partial class Form1
    {
        /// <summary>
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 清理全部正在使用的资源。
        /// </summary>
        /// <param name="disposing">假设应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows 窗口设计器生成的代码

        /// <summary>
        /// 设计器支持所需的方法 - 不要
        /// 使用代码编辑器改动此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            //
            // Form1
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(388, 325);
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "Form1";
            this.Text = "双缓冲技术画图";
            this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);
            this.ResumeLayout(false);

        }

        #endregion
    }
}

Program.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace DoubleBuffer
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

当变化窗口时,会导致图像出现变形,可把窗口属性中的ResizeReDrae 设置为 true

=

时间: 2024-10-13 15:56:09

C#-gdi画图,双缓冲画图,Paint事件的触发---ShinePans的相关文章

C#-gdi绘图,双缓冲绘图,Paint事件的触发---ShinePans

在使用gdi技术绘图时,有时会发现图形线条不够流畅,或者在改变窗体大小时会闪烁不断的现象.(Use DoubleBuffer to solve it!)                                                                                                                                                                              

c# GDI画图 双缓存画图分析

双缓冲绘图分析  1.Windows 绘图原理  我们在 Windows 环境下看到各种元素,如菜单.按钮.窗口.图像,从根本上说,都是“画”出来的.这时的屏幕,就相当于一块黑板,而 Windows 下的各种 GDI 要素,如画笔.画刷等,就相当于彩色粉笔了.我们在黑板上手工画图时,是一笔一划的,电脑亦然.只不过电脑的速度比手工快的太多,所以在我们看起来好像所有的图形文字都是同时出现的. 2.普通绘图方式的局限  上述绘图方式我们暂且称之为普通绘图方式吧.虽然这种方式能满足相当一部分的绘图需要,

Win32双缓冲画图原理

网上有许多文章讲述了如何使用Visual C++程序实现双缓冲,都是用C++面向对象语言写的,可能对很多没有接触过面向对象语言的C语言初学者来说理解起来有些困难,并且有些好心人也只是把源代码贴上去,不做注释,这就使读者读起来更费劲了.    在这里,我会就每一条语句作出解释.其中有一个地方比较有趣,值得讨论(见下文).好了,我们首先看一下双缓冲的基本原理: 一.双缓冲原理及图解 (1)定义设备描述表及位图句柄    HDC hMemDC;    HBITMAP hBitmap;(2)创建一个与窗

GDI+实现双缓冲绘图方法一

private void Form5_MouseMove(object sender, MouseEventArgs e) { int intOX = rectDrawArea.X; int intOY = rectDrawArea.Y; rectDrawArea.X = e.X; rectDrawArea.Y = e.Y; Debug.WriteLine(rectDrawArea.ToString()); //Invalidate(); MyDrawFun(); } private void

GDI+中双缓冲的基本写法

CDC dcMemory; dcMemory.CreateCompatibleDC(&dc); CBitmap bmp; bmp.CreateCompatibleBitmap(&dc,1024,768); dcMemory.SelectObject(&bmp); Graphics _Graphics(dcMemory.m_hDC); _Graphics.DrawImage(_pImage,0,0,1024,768); //这是在GDI+中的写法. dc.BitBlt(0,0,102

简单的GDI+双缓冲的分析与实现

为什么要使用双缓冲绘制 在进行多图元绘制的时候: 因为是要一个一个画上去,所以每画一个图元,系统就要做一次图形的绘制操作,图形的重绘是很占用资源的,特别当需要重绘的图形数量很多的时候,所造成的消耗就特别大,导致闪烁,不流畅等情况.那么如何来解决这个问题呢? 那就是双缓冲. 它的基本原理就是 先在内存中开辟一块虚拟画布,然后将所有需要画的图元一个个先画在这块“虚拟画布”上,最后在一次性将整块“虚拟画布”画到真正的窗体上.因为所有的单个图形的绘制都不是真正的调用显示系统来“画”,所以不会占用显示系统

C#绘图双缓冲

C#绘图双缓冲 C#双缓冲解释: 简单说就是当我们在进行画图操作时,系统并不是直接把内容呈现到屏幕上,而是先在内存中保存,然后一次性把结果输出来,如果没用双缓冲的话,你会发现在画图过程中屏幕会闪的很厉害,因为后台一直在刷新,而如果等用户画完之后再输出就不会出现这种情况,具体的做法,其实也就是先创建一个位图对象,然后把内容保存在里面,最后把图呈现出来. GDI+的双缓冲问题 一直以来的误区:.net1.1 和 .net 2.0 在处理控件双缓冲上是有区别的. .net 1.1 中,使用:this.

Android开发之用双缓冲技术画图

双缓冲技术主要用在绘图,动画效果上,其原理就是:将资源先加载到缓冲区,然后再将缓冲区整个加载到View上面去.双缓冲技术能够有效防止闪烁,提高显示质量. DrawView.java: package com.example.handdraw; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.C

基于c#的双缓冲技术画图

导致画面闪烁的关键原因是:.窗口刷新一次的过程中,每一个图元的重绘都会立即显示到窗口,因此整个窗口中,只要是图元所在的位置,都在刷新,而刷新的时间是有差别的,闪烁现象自然会出现.所以说,此时导致窗口闪烁现象的关键因素并不在于Paint事件调用的次数多少,而在于各个图元的重绘. 因此,,当图数目不多时,窗口刷新的位置也不多,窗口闪烁效果并不严重;当图元数目较多时,绘图窗口进行重绘的图元数量增加,绘图窗口每一次刷新都会导致较多的图元重新绘制,窗口的较多位置都在刷新,闪烁现象自然就会越来越严重.特别是