C#中在某些控件内实现双缓冲绘图的一些问题

来源:互联网 发布:php加密授权 编辑:程序博客网 时间:2024/04/30 04:13

自己在用到双缓冲绘图时候在网上搜索了很多方法,有直接设置,有自己开辟内存方法。到现在为止,我的理解是,如果你要在一个新窗口中直接绘图的话,可以用直接设置双缓冲的方法来搞定。但如果你要在某个控件(以panel举例)内部绘图,其双缓冲的设置方法最好是在内存当中开辟虚拟内存,在内存中绘制好后再在窗口当中显示出来。道理是这个道理,思路大家都知道,但在实现的时候会遇到一些问题。我将自己的遇到一些问题分享出来,免得大家再走弯路。

先贴上一段代码,新建一个窗体,里面只放进去一个控件panel1。在窗体画图事件里面写绘图代码。

 private void Form1_Paint(object sender, PaintEventArgs e)        {            Bitmap bmp = new Bitmap(panel1.ClientRectangle.Width,panel1.ClientRectangle.Height);            Graphics grid = Graphics.FromImage(bmp);            int PX = panel1.Location.X;//panel1的X坐标            int PY = panel1.Location.Y;//panel1的Y坐标                      Graphics g1 = e.Graphics;            Graphics g2 = this.CreateGraphics();            Graphics g3 = e.Graphics;            Graphics g4 = this.CreateGraphics();            g1.DrawLine(new Pen(Color.FromArgb(0x00, 0x00, 0xff)), panel1.Location.X, panel1.Location.Y, 0, 0);//蓝色的笔画从窗体左上角到panel的左上角的线            g2.DrawLine(new Pen(Color.FromArgb(0xff, 0x00, 0x00)), 50, 50, 100, 100);//画一段红线                       grid.DrawLine(new Pen(Color.FromArgb(0x00, 0xff, 0x00)), 0, 0, panel1.ClientRectangle.Width, panel1.ClientRectangle.Height);//在内存中用绿色的笔画panel的对角线            g3.DrawImage(bmp,PX, PY);在窗体中显示出来        }
这段代码是可以实现的,结果如下所示

如果对上面的图做一修改,则结果会发生改变,改动后代码如下,

 private void Form1_Paint(object sender, PaintEventArgs e)        {            Bitmap bmp = new Bitmap(panel1.ClientRectangle.Width,panel1.ClientRectangle.Height);            Graphics grid = Graphics.FromImage(bmp);            int PX = panel1.Location.X;            int PY = panel1.Location.Y;                      Graphics g1 = e.Graphics;            Graphics g2 = this.CreateGraphics();            Graphics g3 = e.Graphics;            Graphics g4 = this.CreateGraphics();            g1.DrawLine(new Pen(Color.FromArgb(0x00, 0x00, 0xff)), panel1.Location.X, panel1.Location.Y, 0, 0);//蓝色的笔画从窗体左上角到panel的左上角的线            g2.DrawLine(new Pen(Color.FromArgb(0xff, 0x00, 0x00)), 50, 50, 100, 100);//画一段红线                       grid.DrawLine(new Pen(Color.FromArgb(0x00, 0xff, 0x00)), 0, 0, panel1.ClientRectangle.Width, panel1.ClientRectangle.Height);//在内存中用绿色的笔画panel的对角线            g4.DrawImage(bmp, PX, PY);在窗体中显示出来        }

把最后一句的Graphics对象变为g4,结果如下:


双缓冲功能并未实现,这说明Graphics对象的创建方式也会影响到结果的实现。

再对代码修改,将

Graphics g4 = this.CreateGraphics();改为
Graphics g4 = panel1.CreateGraphics();

再来观察结果

绿色的线显示了一段,但并没有按我们的预期显示在panel1内部的=的对角线上,这说明双缓冲功能实现了,但线的坐标不对,要更改坐标。

private void Form1_Paint(object sender, PaintEventArgs e)        {            Bitmap bmp = new Bitmap(panel1.ClientRectangle.Width,panel1.ClientRectangle.Height);            Graphics grid = Graphics.FromImage(bmp);            int PX = panel1.Location.X;            int PY = panel1.Location.Y;                      Graphics g1 = e.Graphics;            Graphics g2 = this.CreateGraphics();            Graphics g3 = e.Graphics;            Graphics g4 = panel1.CreateGraphics();            g1.DrawLine(new Pen(Color.FromArgb(0x00, 0x00, 0xff)), panel1.Location.X, panel1.Location.Y, 0, 0);//蓝色的笔画从窗体左上角到panel的左上角的线            g2.DrawLine(new Pen(Color.FromArgb(0xff, 0x00, 0x00)), 50, 50, 100, 100);//画一段红线                       grid.DrawLine(new Pen(Color.FromArgb(0x00, 0xff, 0x00)), 0, 0, panel1.ClientRectangle.Width, panel1.ClientRectangle.Height);//在内存中用绿色的笔画panel的对角线            g4.DrawImage(bmp, 0, 0);在窗体中显示出来        }

总结,容器内部实现双缓冲的关键地方有两个,一个是创建Graphics的方法,一个是DrawLine方法和DrawImage方法的坐标选择要匹配。其中创建图形对象的方法会关联影响到DrawLine方法和DrawImage方法的的坐标选择,其中有一个通常要注意的是,在C#容器内部的线条或者点坐标值通常都是以该容器的左上角为原点的参考值,已经不再以窗体的左上角为原点,其实我们只要分清楚创建的图形对象是在窗体内还是容器内,坐标值就好选择了。另外,使用C#自带的双缓冲类BufferedGraphics实现双缓冲还没搞明白,不乱说了,以免误导像我一样的小白。

1 0