C#图形闪烁
我正在开发一种绘图程序,但在绘制橡皮筋线条时,移动鼠标光标时出现闪烁问题。我希望您能帮助我消除闪烁的线条,以下是代码:C#图形闪烁,c#,.net,winforms,system.drawing,C#,.net,Winforms,System.drawing,我正在开发一种绘图程序,但在绘制橡皮筋线条时,移动鼠标光标时出现闪烁问题。我希望您能帮助我消除闪烁的线条,以下是代码: 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; names
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;
namespace GraphicsTest
{
public partial class Form1 : Form
{
int xFirst, yFirst;
Bitmap bm = new Bitmap(1000, 1000);
Graphics bmG;
Graphics xG;
Pen pen = new Pen(Color.Black, 1);
bool draw = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
bmG = Graphics.FromImage(bm);
xG = this.CreateGraphics();
bmG.Clear(Color.White);
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
xFirst = e.X;
yFirst = e.Y;
draw = true;
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
bmG.DrawLine(pen, xFirst, yFirst, e.X, e.Y);
draw = false;
xG.DrawImage(bm, 0, 0);
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (draw)
{
xG.DrawImage(bm, 0, 0);
xG.DrawLine(pen, xFirst, yFirst, e.X, e.Y);
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
xG.DrawImage(bm, 0, 0);
}
}
}
首先不要使用
CreateGraphics()
,除非你必须这样做。将事件处理程序绑定到OnPaint
并在要刷新曲面时调用Invalidate()
如果不希望它闪烁,则需要加倍缓冲图形表面。最简单的方法是将表单的DoubleBuffered
属性设置为True
如果您打算将此扩展到PictureBox控件,我强烈建议您进行绘图。默认情况下,PictureBox是双缓冲的,允许您更简单地控制绘图区域
代码:
public partial class Form1 : Form
{
int xFirst, yFirst;
Bitmap bm = new Bitmap(1000, 1000);
Graphics bmG;
Pen pen = new Pen(Color.Black, 1);
bool draw = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
bmG = Graphics.FromImage(bm);
bmG.Clear(Color.White);
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
xFirst = e.X;
yFirst = e.Y;
draw = true;
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
bmG.DrawLine(pen, xFirst, yFirst, e.X, e.Y);
draw = false;
Invalidate();
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (draw)
{
Invalidate();
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (draw) {
e.Graphics.DrawImage(bm, 0, 0);
e.Graphics.DrawLine(pen, xFirst, yFirst, e.X, e.Y);
} else {
e.Graphics.DrawImage(bm, 0, 0);
}
}
}
编辑:
另一个问题是,您正在创建一个私有Pen
成员。笔(和画笔,以及许多GDI+对象)表示非托管对象的句柄,这些句柄需要处理,否则程序将泄漏。使用语句将它们包装在中(首选且异常安全的方式),或者在表单的dispose
方法中显式地处理它们
或者,在System.Drawing中,您可以访问一些不需要(也不应该)处理的预制笔和画笔。像这样使用它们:
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (draw) {
e.Graphics.DrawImage(bm, 0, 0);
e.Graphics.DrawLine(Pens.Black, xFirst, yFirst, e.X, e.Y);
} else {
e.Graphics.DrawImage(bm, 0, 0);
}
}
它闪烁的原因是您正在绘制背景(立即显示在屏幕上,擦除线条),然后叠加线条。因此,该行不断消失和出现,显示闪烁
解决这一问题的最佳方案称为双缓冲。您要做的是将整个图像绘制为“屏幕外”位图,并仅在完成后在屏幕上显示。因为您只显示完成的图像,所以没有闪烁效果。您只需将此设置为.DoubleBuffered=true,即可让WinForms为您完成所有繁重的工作
注意:您不应该真正在绘制处理程序之外进行绘制-理想情况下,您应该使需要重新绘制的区域无效(),然后绘制处理程序将只重新绘制该区域(根据需要使用任何重叠线等)。修复并运行代码
public partial class Form1 : Form
{
int x1, y1, x2, y2;
bool drag = false;
Bitmap bm = new Bitmap(1000, 1000);
Graphics bmg;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
bmg = Graphics.FromImage(bm);
}
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
drag = true;
x1 = e.X;
y1 = e.Y;
}
private void pictureBox_MouseUp(object sender, MouseEventArgs e)
{
drag = false;
bmg.DrawLine(Pens.Black, x1, y1, e.X, e.Y);
pictureBox.Invalidate();
}
private void pictureBox_MouseMove(object sender, MouseEventArgs e)
{
if (drag)
{
x2 = e.X;
y2 = e.Y;
pictureBox.Invalidate();
}
}
private void pictureBox_Paint(object sender, PaintEventArgs e)
{
if (drag) {
e.Graphics.DrawImage(bm, 0, 0);
e.Graphics.DrawLine(Pens.Black, x1, y1, x2, y2);
}
else {
e.Graphics.DrawImage(bm, 0, 0);
}
}
}
我使用它来管理面板中的双缓冲:
myPanel.GetType().GetMethod("SetStyle",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic).Invoke(myPanel,
new object[]
{
System.Windows.Forms.ControlStyles.UserPaint |
System.Windows.Forms.ControlStyles.AllPaintingInWmPaint |
System.Windows.Forms.ControlStyles.DoubleBuffer, true
});
窗体或控件中是否启用了双缓冲?感谢您的回答和建议,我将尝试修复它。我修复了代码中的一个小问题,您可以删除xG对象,并在paint事件中使用PaintEventArgs的e.Graphics
属性来获取窗体的图形上下文。是的,它可以工作。谢谢。现在我也了解了Invalidate()的用法。很好。我希望我至少能投你1000^1000^1000次!这救了我的命,伙计在VS2012上以.NET Framework 4.0为目标尝试您的代码,但不起作用。获取访问e.X和e.Y的Form1_Paint事件中的错误,这些错误由于某些原因无效。感谢您的详细解释更改了我的解决方案,我的鼠标移动事件停止工作,哈哈