Reputation: 41
I want to make a simple application that allows to draw a line. When you click with the mouse you set the initial coords of the line. Then, by moving the mouse, you lengthen or shorten the line. So, every time my panel (I'm using System.Windows.Forms) detect that my mouse's moving, it should draw a new line, as this will be different (even by one pixel) from the previous one. The main problem is, first, that I don't know exactly how to handle repainting in C# (I used to use Java, and for some aspects repainting was easier) and second, that when I call the panel.Invalidate() method, everything is flickering. I also tried to use the panel.Invalidate(Region r) method by using as parameter a rectangle, but it still flickers.
This is the class where my panel operates. The Road object contains the method that paints the line. In the panel1_paint(object sender, PaintEventArgs e) method I only color the background. In the panel1_MouseMove(object sender, MouseEventArgs e) method I paint the line.
partial class Form1 : Form
{
Manager manager;
Graphics g;
Road road;
Point initPosition;
bool roadOn;
bool mouseDown;
public Form1(Manager manager)
{
InitializeComponent();
this.manager = manager;
g = panel1.CreateGraphics();
road = new Road(0, 0, 0, 0, new Pen(Color.Gray, 10));
initPosition = new Point(0, 0);
roadOn = false;
mouseDown = false;
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
panel1.BackColor = Color.LightGray;
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
Point position = Cursor.Position;
if(panel1.ClientRectangle.Contains(position))
{
if(e.KeyChar.ToString() == Keys.R.ToString().ToLower())
{
roadOn = true;
}
}
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = true;
initPosition = Cursor.Position;
road.X = initPosition.X;
road.Y = initPosition.Y;
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
panel1.Invalidate();
panel1.Dispose();
panel1.Update();
Point position = Cursor.Position;
if(roadOn)
{
if(mouseDown)
{
road.X2 = position.X;
road.Y2 = position.Y;
road.paint(g);
}
}
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
}
}
This is the Road class:
class Road : GameObject
{
Pen pen;
public Pen Pen
{
get { return pen; }
set { pen = value; }
}
int x2;
public int X2
{
get { return x2; }
set { x2 = value; }
}
int y2;
public int Y2
{
get { return y2; }
set { y2 = value; }
}
public Road(int x1, int y1, int x2, int y2, Pen pen) : base(x1, y1)
{
this.pen = pen;
}
override public void paint(Graphics g)
{
g.DrawLine(pen, x, y, x2, y2);
}
}
Upvotes: 0
Views: 504
Reputation: 3750
Panel
control has a DoubleBuffered
property but it's protected. The best solution is then extend it to override the property to true and use the new class to draw:
Create a class inheriting from Panel:
//Make it sealed so you can call DoubleBuffered from the constructor safely.
public sealed class DoubleBufferedPanel : Panel
{
public DoubleBufferedPanel()
{
//I want this class only for drawing so force the value to true here
DoubleBuffered = true;
}
}
Replace your panel in the Form with an instance of the previously created class.
With only this minor change you should see zero-flicker drawing.
Hope this helps!
Upvotes: 1
Reputation: 5930
I was having the same issue 2 weeks ago. The problem is that you have to set custom control styles to allow double buffer.
SetStyle( ControlStyles.OptimizedDoubleBuffer, true );
and You can override CreateParams property like so:
protected override CreateParams CreateParams
{
get {
CreateParams cp = base.CreateParams; cp.ExStyle = cp.ExStyle | 0x20;
return cp;
}
}
Another problem is that you use Invalidate() method which requests full validation of a control. Use Refresh() method instead and remove Invalidate() and Update() methods.
Hope this will help :)
Upvotes: 0