对象目前在别处使用。图片框

时间:2015-09-23 21:00:07

标签: c# gdi+ picturebox

我试图在应用程序中实现Langton的Ant算法。它有1个Button和1个PictureBox控件。这是代码:

    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:对象当前正在其他地方使用。我是否锁定图像并不重要。当我将间隔增加到250毫秒或以上时,不会发生例外

1 个答案:

答案 0 :(得分:2)

两件事:

  1. 您正在从另一个线程访问WinForms UI组件。只能从UI线程触摸(甚至读取)GUI组件。
  2. 您正在操纵Bitmap已经在使用的PictureBox,而应该直接用新图片替换它,或者先使用Clone方法,然后重新分配,不要忘记旧位图的Dispose,如果有的话。
  3. 试试这个:

    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();
            }
        } );
    }
    

    另外,避免GetPixelSetPixel,它们非常慢。而是这样做:

    BitmapData data = bmp.LockBits();
    Byte[] buffer = new Byte[ ... ];
    Marshal.Copy( data.Scan0, buffer, ... );
    
    // Manipulate raw pixel data contained in buffer here
    
    bmp.UnlockBits( data );