Stop all that Invalidate - it is the cause of the flickering. You are repainting the whole panel with an extreme frequency...
Your second problem is the way you try to handle you Graphics object...You create an image and from that a Graphics object and then assign it back to the panel as background...This is a total waste IMHO...
Try drawing directly to the Graphics object of the panel!!!
public partial class Form1 : Form
{
Graphics g;
bool mouse_down = false;
public Form1 ( )
{
InitializeComponent ( );
}
private void panel1_MouseDown ( object sender, MouseEventArgs e )
{
mouse_down = true;
}
private void panel1_MouseMove ( object sender, MouseEventArgs e )
{
if ( mouse_down )
{
g.FillRectangle ( Brushes.Black, new Rectangle ( e.X, e.Y, 5, 5 ) );
}
}
private void panel1_MouseUp ( object sender, MouseEventArgs e )
{
mouse_down = false;
}
private void Form1_Load ( object sender, EventArgs e )
{
g = panel1.CreateGraphics ( );
}
}
[EDIT]
As Sergey properly stated, my solution is very clumsy in a way that it's only solves the immediate problem of the presented code, but do not addresses the real problem - persistent drawing!
To explain the problem here a very short explanation of how painting in Windows works:
Your window (panel or any other control that part of it) is drawing itself - means it is not Windows the OS who paint those nice borders and buttons on your window but the window itself (and its parts) has the knowledge how to be painted...
But! The when (and what part) is synchronized by Windows via sending paint message (WM_PAINT) to each and every window according to changes in it state and/or visibility. For instance a window became visible (by closing the window on top of it) and Windows send it a paint message to notify it about the event.
Now, your window (the panel) has a lot of painting on it that was created from the mouse events, but what will happen if some other window overlaps (hides) a part of your window? That hidden part will be lost and when you window became visible a second time - and receive a paint message - no-one will know how to re-create it...
There should be two main methods to persists the knowledge of how to re-create the drawing:
1. Record all the paintings you made in a kind of queue and upon paint message use that queue to draw all the paintings again. It can be very useful for a more sophisticated paint program that can handle every painted 'object' (like circle, rectangle or line) individually...
2. Create a shadow copy - disconnected from the main window - of your painting and copy it back upon paint message
I will show a sample for the second approach (as it's much more sample) now:
public partial class Form1 : Form
{
Graphics g;
Graphics g_shadow;
Bitmap bmp;
bool mouse_down = false;
public Form1 ( )
{
InitializeComponent ( );
}
private void panel1_MouseDown ( object sender, MouseEventArgs e )
{
mouse_down = true;
}
private void panel1_MouseMove ( object sender, MouseEventArgs e )
{
if ( mouse_down )
{
g.FillRectangle ( Brushes.Black, new Rectangle ( e.X, e.Y, 5, 5 ) );
g_shadow.FillRectangle ( Brushes.Black, new Rectangle ( e.X, e.Y, 5, 5 ) );
}
}
private void panel1_MouseUp ( object sender, MouseEventArgs e )
{
mouse_down = false;
}
private void Form1_Load ( object sender, EventArgs e )
{
g = panel1.CreateGraphics ( );
bmp = new Bitmap ( panel1.Width, panel1.Height );
g_shadow = Graphics.FromImage ( bmp );
}
private void panel1_Paint ( object sender, PaintEventArgs e )
{
e.Graphics.DrawImageUnscaled ( bmp, e.ClipRectangle );
}
}