我有一个基本上像绘图应用程序的程序.但是,我的程序有一些闪烁的问题.我的代码中有以下行(它应该摆脱闪烁 - 但不是):
this.SetStyle(ControlStyles.AllPaintingInWmPaint
| ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
Run Code Online (Sandbox Code Playgroud)
我的代码(减去形状的超类和子类如下:
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 Paint
{
public partial class Paint : Form
{
private Point startPoint;
private Point endPoint;
private Rectangle rect = new Rectangle();
private Int32 brushThickness = 0;
private Boolean drawSPaint = false;
private List<Shapes> listOfShapes = new List<Shapes>();
private Color currentColor;
private Color currentBoarderColor;
private Boolean IsShapeRectangle = false;
private Boolean IsShapeCircle = false;
private Boolean IsShapeLine = false;
public SPaint()
{
InitializeComponent();
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
currentColor = Color.Red;
currentBoarderColor = Color.DodgerBlue;
IsShapeRectangle = true;
}
private void panelArea_Paint(object sender, PaintEventArgs e)
{
Graphics g = panelArea.CreateGraphics();
if (drawSPaint == true)
{
Pen p = new Pen(Color.Blue);
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
if (IsShapeRectangle == true)
{
g.DrawRectangle(p, rect);
}
else if (IsShapeCircle == true)
{
g.DrawEllipse(p, rect);
}
else if (IsShapeLine == true)
{
g.DrawLine(p, startPoint, endPoint);
}
}
foreach (Shapes shape in listOfShapes)
{
shape.Draw(g);
}
}
private void panelArea_MouseDown(object sender, MouseEventArgs e)
{
startPoint.X = e.X;
startPoint.Y = e.Y;
drawSPaint = true;
}
private void panelArea_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
if (e.X > startPoint.X)
{
rect.X = startPoint.X;
rect.Width = e.X - startPoint.X;
}
else
{
rect.X = e.X;
rect.Width = startPoint.X - e.X;
}
if (e.Y > startPoint.Y)
{
rect.Y = startPoint.Y;
rect.Height = e.Y - startPoint.Y;
}
else
{
rect.Y = e.Y;
rect.Height = startPoint.Y - e.Y;
}
panelArea.Invalidate();
}
}
private void panelArea_MouseUp(object sender, MouseEventArgs e)
{
endPoint.X = e.X;
endPoint.Y = e.Y;
drawSPaint = false;
if (rect.Width > 0 && rect.Height > 0)
{
if (IsShapeRectangle == true)
{
listOfShapes.Add(new TheRectangles(rect, currentColor, currentBoarderColor, brushThickness));
}
else if (IsShapeCircle == true)
{
listOfShapes.Add(new TheCircles(rect, currentColor, currentBoarderColor, brushThickness));
}
else if (IsShapeLine == true)
{
listOfShapes.Add(new TheLines(startPoint, endPoint, currentColor, currentBoarderColor, brushThickness));
}
panelArea.Invalidate();
}
}
private void rectangleToolStripMenuItem_Click(object sender, EventArgs e)
{
IsShapeRectangle = true;
IsShapeCircle = false;
IsShapeLine = false;
}
private void ellipseToolStripMenuItem_Click(object sender, EventArgs e)
{
IsShapeRectangle = false;
IsShapeCircle = true;
IsShapeLine = false;
}
private void lineToolStripMenuItem_Click(object sender, EventArgs e)
{
IsShapeCircle = false;
IsShapeRectangle = false;
IsShapeLine = true;
}
private void ThicknessLevel0_Click(object sender, EventArgs e)
{
brushThickness = 0;
}
private void ThicknessLevel2_Click(object sender, EventArgs e)
{
brushThickness = 2;
}
private void ThicknessLevel4_Click(object sender, EventArgs e)
{
brushThickness = 4;
}
private void ThicknessLevel6_Click(object sender, EventArgs e)
{
brushThickness = 6;
}
private void ThicknessLevel8_Click(object sender, EventArgs e)
{
brushThickness = 8;
}
private void ThicknessLevel10_Click(object sender, EventArgs e)
{
brushThickness = 10;
}
private void ThicknessLevel12_Click(object sender, EventArgs e)
{
brushThickness = 12;
}
private void ThicknessLevel14_Click(object sender, EventArgs e)
{
brushThickness = 14;
}
private void FillColour_Click(object sender, EventArgs e)
{
ColorDialog fillColourDialog = new ColorDialog();
fillColourDialog.ShowDialog();
currentColor = fillColourDialog.Color;
panelArea.Invalidate();
}
private void button1_Click(object sender, EventArgs e)
{
ColorDialog fillColourDialog = new ColorDialog();
fillColourDialog.ShowDialog();
currentBoarderColor = fillColourDialog.Color;
panelArea.Invalidate();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我该如何阻止闪烁?
*更新:*当我直接在表单上绘图时,这段代码实际上很有效.但是,当我尝试在面板上绘图时,闪烁成为一个问题
vip*_*per 60
对于"更干净的解决方案"并且为了继续使用基本面板,您可以简单地使用Reflection来实现双缓冲,方法是将此代码添加到包含要在其中绘制的面板的表单中
typeof(Panel).InvokeMember("DoubleBuffered",
BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
null, DrawingPanel, new object[] { true });
Run Code Online (Sandbox Code Playgroud)
其中"DrawingPanel"是您要进行双缓冲的面板的名称.
自从问到这个问题以来,我知道已经过了很多时间,但这可能会对未来的某些人有所帮助.
Big*_*Bug 53
终于解决了闪烁问题.由于我在面板而不是表单上绘图,下面的代码行无法解决闪烁问题:
this.SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer,
true);
Run Code Online (Sandbox Code Playgroud)
SetStyle必须是'YourProject.YourProject'类型(或从它派生),因此,你必须创建一个类(这样你就可以使用MyPanel,它将从SPaint.SPaint派生,因此允许你直接使用doublebuffering小组 - 而不是形式):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SPaint;
namespace YourProject
{
public class MyPanel : System.Windows.Forms.Panel
{
public MyPanel()
{
this.SetStyle(
System.Windows.Forms.ControlStyles.UserPaint |
System.Windows.Forms.ControlStyles.AllPaintingInWmPaint |
System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer,
true);
}
}
}
Run Code Online (Sandbox Code Playgroud)
完成此操作后(尽管您真的不应该编辑设计器代码,除非您真正知道自己在做什么),否则您必须编辑Form.Designer.cs.在此文件中,您将找到如下所示的代码:
this.panelArea = new YourProject.MyPanel();
Run Code Online (Sandbox Code Playgroud)
上述行需要更改为:
this.panelArea = new MyPanel();
Run Code Online (Sandbox Code Playgroud)
完成这些步骤后,我的绘画程序不再闪烁.
对于其他任何有同样问题的人来说,问题终于解决了.
请享用!
小智 28
将其复制并粘贴到您的项目中
protected override CreateParams CreateParams
{
get
{
CreateParams handleParam = base.CreateParams;
handleParam.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
return handleParam;
}
}
Run Code Online (Sandbox Code Playgroud)
这样就可以从表单级别向所有控件进行双缓冲,否则需要为每个控件单独启用双缓冲...您可能需要在此之后微调双缓冲区,因为覆盖双缓冲可能会产生不必要的副作用.
ohm*_*ama 15
我曾经也有过一样的问题.我永远无法100%摆脱闪烁(见第2点),但我用过这个
protected override void OnPaint(PaintEventArgs e) {}
Run Code Online (Sandbox Code Playgroud)
以及
this.DoubleBuffered = true;
Run Code Online (Sandbox Code Playgroud)
闪烁的主要问题是确保你
OnPaint每次需要重绘表单时,winforms都会调用该方法.有许多方法可以取消验证,包括在表单上移动鼠标光标有时可以调用重绘事件.
而且重要的一点是OnPaint,你是不是每次都从头开始,而是从你所在的地方开始,如果你填充背景颜色,你可能会变得闪烁.
最后你的gfx对象.在内部,OnPaint您将需要重新创建图形对象,但仅限于屏幕大小已更改.重新创建对象是非常昂贵的,它需要在重新创建之前进行处理(垃圾收集不能100%正确处理它,所以说文档).我创建了一个类变量
protected Graphics gfx = null;
Run Code Online (Sandbox Code Playgroud)
然后在本地使用它OnPaint,但这是因为我需要在我班级的其他位置使用gfx对象.否则不要这样做.如果您只是在OnPaint中绘画,那么请使用e.Graphics!!
// clean up old graphics object
gfx.Dispose();
// recreate graphics object (dont use e.Graphics, because we need to use it
// in other functions)
gfx = this.CreateGraphics();
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助.