对象当前在别处使用。图片框
Object is currently used elsewhere. PictureBox
我试图在一个应用程序中实现 Langton 的 Ant 算法。它有 1 个按钮和 1 个图片框控件。这是代码:
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);
}
}
在 run()
方法中,Bitmap b = (Bitmap)pictureBox1.Image;
处始终存在异常,它表示 InvalidOperatopnException: Object is currently in use elshere。我是否锁定图像并不重要。当我将间隔增加到 250 毫秒或以上时,不会发生异常
两件事:
- 您正在从另一个线程访问 WinForms UI 组件。 GUI 个组件只能从 UI 线程访问(甚至读取)。
- 您正在操纵
PictureBox
已经在使用的 Bitmap
,您应该直接用新图像替换它,或者先使用 Clone
方法,然后重新分配,并且不要忘记旧位图的Dispose
,如果有的话。
试试这个:
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();
}
} );
}
此外,请避免使用 GetPixel
和 SetPixel
,它们非常慢。而是这样做:
BitmapData data = bmp.LockBits();
Byte[] buffer = new Byte[ ... ];
Marshal.Copy( data.Scan0, buffer, ... );
// Manipulate raw pixel data contained in buffer here
bmp.UnlockBits( data );
我试图在一个应用程序中实现 Langton 的 Ant 算法。它有 1 个按钮和 1 个图片框控件。这是代码:
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);
}
}
在 run()
方法中,Bitmap b = (Bitmap)pictureBox1.Image;
处始终存在异常,它表示 InvalidOperatopnException: Object is currently in use elshere。我是否锁定图像并不重要。当我将间隔增加到 250 毫秒或以上时,不会发生异常
两件事:
- 您正在从另一个线程访问 WinForms UI 组件。 GUI 个组件只能从 UI 线程访问(甚至读取)。
- 您正在操纵
PictureBox
已经在使用的Bitmap
,您应该直接用新图像替换它,或者先使用Clone
方法,然后重新分配,并且不要忘记旧位图的Dispose
,如果有的话。
试试这个:
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();
}
} );
}
此外,请避免使用 GetPixel
和 SetPixel
,它们非常慢。而是这样做:
BitmapData data = bmp.LockBits();
Byte[] buffer = new Byte[ ... ];
Marshal.Copy( data.Scan0, buffer, ... );
// Manipulate raw pixel data contained in buffer here
bmp.UnlockBits( data );