Reputation: 169
I was trying to implement Langton's Ant algorithm in an application. It has 1 Button and 1 PictureBox control. This is the code:
int x = 100, y = 100;
int angle = 90;
private void button1_Click(object sender, EventArgs e)
{
Bitmap resultImage = new Bitmap(pictureBox1.Width, pictureBox1.Height, PixelFormat.Format24bppRgb);
for (int i = 0; i < resultImage.Height; i++)
{
for (int z = 0; z < resultImage.Width; z++)
{
resultImage.SetPixel(z, i, Color.White);
}
}
pictureBox1.Image = resultImage;
Thread t = new Thread(new ThreadStart(run));
t.Start();
}
public void run()
{
while (true)
{
lock (pictureBox1.Image)
{
//Exception takes place here.
Bitmap b = (Bitmap)pictureBox1.Image;
string name = b.GetPixel(x, y).Name;
if (b.GetPixel(x, y).Name == "ffffffff")
{
angle -= 90;
b.SetPixel(x, y, Color.Black);
}
else
{
angle += 90;
b.SetPixel(x, y, Color.White);
}
pictureBox1.Image = b;
x += (int)Math.Cos(angle * Math.PI / 180);
y += (int)Math.Sin(angle * Math.PI / 180);
}
Thread.Sleep(50);
}
}
In run()
method there's always an exception at Bitmap b = (Bitmap)pictureBox1.Image;
and it says InvalidOperatopnException: Object is currently in use elsewhere. It doesn't matter whether I lock the image or not. The exception doesn't occur when I increase the interval to 250 ms or above
Upvotes: 0
Views: 1873
Reputation: 155035
Two things:
Bitmap
that's already in-use by the PictureBox
, instead you should either outright replace it with a new image, or use the Clone
method first, then re-assign, and don't forget to Dispose
of the old bitmap, if any.Try this:
private void ButtonClick() {
Thread thread = new Thread( this.BackgroundThread );
thread.Start(); // ideally, replace this with the .NET Task library
}
private void BackgroundThread() {
Bitmap bmp = new Bitmap( ... );
// do bitmap pixel-setting here
this.Invoke( () => {
Bitmap old = this.pictureBox1.Image as Bitmap;
this.pictureBox1.Image = bmp;
if( old != null ) {
old.Dispose();
}
} );
}
Also, avoid GetPixel
and SetPixel
, they're very slow. Instead do this:
BitmapData data = bmp.LockBits();
Byte[] buffer = new Byte[ ... ];
Marshal.Copy( data.Scan0, buffer, ... );
// Manipulate raw pixel data contained in buffer here
bmp.UnlockBits( data );
Upvotes: 3