我有一个WinForms应用程序,我必须在控件之间画一些线。这些行必须是持久的,所以我覆盖了OnPaint()
事件形式。
问题在于,线条的重新绘制不是很顺利。
我正在创建如下图形:
Graphics g;
g = this.CreateGraphics();
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.FillRectangle(Brushes.White, this.ClientRectangle);
绘制如下行:
public void lineDraw(Control L1, Control L2) {
using (Pen pen = new Pen(Color.Black, 4)) {
pen.StartCap = System.Drawing.Drawing2D.LineCap.Flat;
pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
int x1, x2, y1, y2;
//choose x/y coordinates
g.DrawLine(pen, x1, y1, x2, y2);
}
}
我可以设置任何属性来改善绘制图形的平滑度吗?
答案 0 :(得分:4)
图像显示在控件(或表单)上。
无论何时调整控件(或窗体)的大小,最小化/最大化,部分遮挡或移动,都必须(部分)重绘。发生这种情况时,必须重绘的控件部分被称为无效。
当无效时,控件会执行以下操作:
OnPaintBackground
:这会使用背景颜色填充无效区域。OnPaint
:这会在背景上绘制文字和图片。OnPaint
会导致闪烁您已覆盖控件的OnPaint
method。每次重绘控件时,您都会看到控件的闪光,其中仅绘制了背景颜色。这是在调用OnPaintBackground
之后调用OnPaint
之前。
如果您有静态图像(即它永远不会改变):
Load
事件中:创建一个新的Bitmap
object。Bitmap
对象分配给控件的BackgroundImage
property。如果您的静态图像必须在控件调整大小时调整大小:
OnResize
method并在其中创建新的Bitmap
。使用控件ClientSize
property获取Bitmap
。Bitmap
对象分配给控件的BackgroundImage
属性。如果您有动画图片:
Load
事件中,将控件的DoubleBuffered
property设置为true
。设置此项可防止您看到的闪烁,因为它使用不可见的缓冲区来绘制控件。OnPaint
method。获取控件的Graphics
context并直接在控件上绘制线条和形状。Timer
object,并在其回调方法中调用控件的Invalidate
method,然后调用Update
method(as shown here)。将计时器设置为触发,例如,每40毫秒。答案 1 :(得分:2)
你可能不应该在这里使用CreateGraphics
,更重要的是,不要使用局部变量来存储图形对象。使用从paint事件获取的图形对象,并根据需要使其无效。
protected override void OnPaint(PaintEventArgs e) {
e.Graphics.Clear(Color.White);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (Pen pen = new Pen(Color.Black, 4)) {
pen.StartCap = Drawing2D.LineCap.Flat;
pen.EndCap = Drawing2D.LineCap.ArrowAnchor;
int x1, x2, y1, y2;
//choose x/y coordinates
e.Graphics.DrawLine(pen, x1, y1, x2, y2);
}
base.OnPaint(e);
}
答案 2 :(得分:0)
这是我的方式,它为我工作
//FormMain.cs
private const float DisplayRatio = 6;
private Bitmap _bmpDisp; //use an in-memory bitmap to Persistent graphics
private Graphics _grpDisp4Ctl;
private Graphics _grpDisp4Bmp;
private Point _ptOldDsp;
private void FormMain_Shown(object sender, EventArgs e)
{
_grpDisp4Ctl = CreateGraphics();
_grpDisp4Ctl.SetHighQulity();
_bmpDisp = new Bitmap(ClientSize.Width, ClientSize.Height);
_grpDisp4Bmp = Graphics.FromImage(_bmpDisp);
_grpDisp4Bmp.SetHighQulity();
_ptOldDsp = new Point(
(int)((MousePosition.X - SystemInformation.VirtualScreen.Left) / DisplayRatio),
(int)((MousePosition.Y - SystemInformation.VirtualScreen.Top) / DisplayRatio)
);
}
private void UpdateDisplay(MouseHookEvent mhep) //your implement
{
var ptNew = mhep.Position;
ptNew.Offset(new Point(-SystemInformation.VirtualScreen.Left, -SystemInformation.VirtualScreen.Top));
ptNew.X = (int)(ptNew.X / DisplayRatio);
ptNew.Y = (int)(ptNew.Y / DisplayRatio);
_grpDisp4Ctl.DrawLine(Pens.White, _ptOldDsp, ptNew); //draw smooth lines to mem and ui
_grpDisp4Bmp.DrawLine(Pens.White, _ptOldDsp, ptNew);
_ptOldDsp = ptNew;
}
private void FormMain_Paint(object sender, PaintEventArgs e)
{
// like vb6's auto redraw :)
e.Graphics.DrawImage(_bmpDisp, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel);
}
//common.cs
internal static void SetHighQulity(this Graphics g)
{
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
}
答案 3 :(得分:0)
我知道这是一篇较旧的帖子,但您也可以尝试将表单的DoubleBuffered属性设置为TRUE,请阅读以下内容:
“缓冲图形可以减少或消除由此引起的闪烁 逐步重绘显示表面的部分。缓冲的 图形要求更新的图形数据首先写入a 缓冲。然后快速写入图形缓冲区中的数据 显示表面记忆。显示的相对快速切换 图形存储器通常会减少闪烁,否则可能会减少闪烁 发生“。