Reputation: 3995
I'm using PictureBox control to draw complicated charts, and to optimize for performance i use a cache Bitmap for each layer of the drawing, and draw them on the control image, the upper layers have transparent backgrounds, i need to clear them and redraw on every change.
Assuming g instance of Graphics class of the Bitmap, using g.Clear(Color.White)
draws a white rectangle over everything and so hiding lower layers, and g.Clear(Color.Transparent)
draws Transparent rectangle over, what means doing nothing.
Isn't there a way to clear the Bitmap returning it to its original state?
Upvotes: 4
Views: 10209
Reputation: 347
private void btn_CancelImage_Click(object sender, EventArgs e)
{
DialogResult dialogResult = MessageBox.Show("Cancel and delete this Image?", "Cancel", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
ClearImage();
pictureBox1.Refresh();
}
else if (dialogResult == DialogResult.No)
{
return;
}
}
public void ClearImage()
{
Graphics g = Graphics.FromImage(ImageBitmap);
g.Clear(Color.White);
}
Upvotes: 6
Reputation: 54433
This is maybe not the answer you were looking for but I think it is an insteresting alternative to what you have.
Instead of having to draw all the layers upwards from every change, I stack as many layers on top of each other by nesting a number of PictureBoxes
into one bottom PictureBox pBox0
:
List<PictureBox> Layers = new List<PictureBox>();
private void Form1_Load(object sender, EventArgs e)
{
Layers.Add(pBox0);
setUpLayers(pBox0 , 20); // stacking 20 layers onto the botton one
timer1.Start(); // simulate changes
}
The stacking is set up like this:
void setUpLayers(Control parent, int count)
{
for (int i = 0; i < count; i++)
{
PictureBox pb = new PictureBox();
pb.BorderStyle = BorderStyle.None;
pb.Size = parent.ClientSize;
Bitmap bmp = new Bitmap(pb.Size.Width,pb.Size.Height,PixelFormat.Format32bppPArgb);
pb.Image = bmp;
pb.Parent = i == 0 ? pBox0 : Layers[i - 1];
Layers.Add(pb);
}
}
For best performance I use Format32bppPArgb
as the pixel format.
For testing I run a Tick
event that randomly draws onto a layer:
Random R = new Random(9);
private void timer1_Tick(object sender, EventArgs e)
{
int l = R.Next(Layers.Count-1) + 1;
Bitmap bmp = (Bitmap) Layers[l].Image;
using (Graphics G = Graphics.FromImage(Layers[l].Image))
{
G.Clear(Color.Transparent);
using (Font font = new Font("Consolas", 33f))
G.DrawString(l + " " + DateTime.Now.Second , font, Brushes.Gold,
R.Next(bmp.Size.Width), R.Next(bmp.Size.Height));
}
Layers[l].Image = bmp;
}
To collect all layers into one Bitmap you would make use of the DrawToBitmap
method:
Bitmap GetComposite(Control ctl)
{
Bitmap bmp = new Bitmap(ctl.ClientSize.Width, ctl.ClientSize.Height,
PixelFormat.Format32bppArgb);
ctl.DrawToBitmap(bmp, ctl.ClientRectangle);
return bmp;
}
The result can then be saved or used in any other way..
Note that creating too many layers this way will hit a limit for window handles; I hit that limit at around 90 layers. If you need more that a few dozen layers a more intricate caching strategy is called for..
Upvotes: 1