I have a program that is essentially like a paint application. However, my program has some flickering issues. I have the following line in my code (which should get rid of flickering - but doesn't):
this.SetStyle(ControlStyles.AllPaintingInWmPaint
| ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
my code(minus the super and sub classes for the shapes is as follows:
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();
}
}
}
How do i stop the flickering?
*UPDATE:*This code actually works great when i'm drawing directly on the form. However, when i try to draw on the panel, flickering becomes an issue
In this condition you have to enable double buffer . Open current form and go to form properties and apply double buffer true; or you can also write this code .
In form load.
Double buffering is not going to be of much help here I'm afraid. I ran into this a while ago and ended up adding a separate panel in a rather clumsy way but it worked for my application.
Make the original panel that you have ( panelArea ) a transparent area, and put it on top of a 2nd panel, which you call panelDraw for example. Make sure to have panelArea in front. I whipped this up and it got rid of the flickering, but left the shape that was being drawn smeared out so it's not a full solution either.
A transparent panel can be made by overriding some paint actions from the original panel:
The idea is to handle drawing the temporary shape during the MouseMove event of the 'panelArea' and ONLY repaint the 'panelDraw' on the MouseUp Event.
Finally solved the flickering. Since I was drawing on a panel instead of the form the line of code below will not solve the flickering:
SetStyle must be of type 'YourProject.YourProject' (or derived from it) hence, you have to create a class as such (so that you can use MyPanel which will be derived from SPaint.SPaint and hence allowing you to use doublebuffering directly for the panel - rather than the form):
After you've done this(although you should really never edit the designer code unless you truly know what you're doing) you'll have to edit the Form.Designer.cs. Inside this file you will find code that looks like this:
The above line needs to be changed to:
After I completed these steps, my paint program no longer flickers.
For anyone else having the same issue, the problem is finally solved.
Enjoy!
if all of the above doesn't work you can always create your own double buffer link to Microsofts tutorial: https://docs.microsoft.com/en-us/dotnet/framework/winforms/advanced/how-to-reduce-graphics-flicker-with-double-buffering-for-forms-and-controls
hopes it works for you
Can you try using a timer and boolean to check if mouse is down, and paint in that spot, using a variable again check if user has moved his mouse, if moved paint that spot too etc.
Or just check if mouse down(via boolean that sets true when mouse is down) using a timer and paint it considering you are probably trying to just paint one pixel, not like you have shadow etc. Instead of using actual mousedown. So you check every 1 second instead of 0.0001 and it wont flicker. Or vice-versa, try it with your own times.
I know this is really old question but maybe someone will find it useful.
I'd like to make little enhancement to viper's answer.
You can make simple extension to Panel class and hide setting property through reflection.
If your Panel variable's name is myPanel you can just call
myPanel.SetDoubleBuffered();
and that's it. Code looks much cleaner.