Picturebox获得大红色X但我无法检测或修复它

时间:2013-04-17 13:13:28

标签: c# winforms thread-safety picturebox aforge

我目前正在与AForge合作,并有一个新的帧事件,将帧作为位图发布到图片框中。它有90%的时间很棒......除非我在winform上捣乱。更改组合框,移动窗口或任何类似的风险会导致Picturebox从视频切换到大红色X.下面的代码示例:

    private void connectButton_Click(object sender, EventArgs e)
    {
        try
        {
            cam = new VideoCaptureDevice(captureDevices[CameraSelectComboBox.SelectedIndex].MonikerString);
            cam.NewFrame -= Handle_New_Frame; //Just to avoid the possibility of a second event handler being put on
            cam.NewFrame += new AForge.Video.NewFrameEventHandler(Handle_New_Frame);
            cam.Start();
        }
        catch
        {
            MessageBox.Show("An error has occured with connecting to the specified webcam. The application will now close!");
            Application.Exit();
        }
    }

    private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs)
    {

        try
        {
            if (bitmap != null)
                bitmap.Dispose(); //Without this, memory goes nuts
            bitmap = new Bitmap(eventArgs.Frame);
        }
        catch { }

        //Draw some stuff on the images
        bitmap = AdjustBrightness(bitmap, brightnessMeter);
        bitmap = ApplyContrast(contrastMeter, bitmap);
        bitmap = Draw_Top_Line(bitmap);
        bitmap = Draw_Bottom_Line(bitmap);

        //Set the image into the picturebox
        this.Invoke((MethodInvoker)delegate
        {
            videoPictureBox1.Image = bitmap;
            frameRate++; //Keep track of the frame rate
        });

        GC.Collect(); //Without this, memory goes nuts

        this.Invoke((MethodInvoker)delegate {
            videoPictureBox1.Refresh(); //NOT NECESSARY. JUST TRYING TO FIX THE BIG RED X!
        });

        if (videoPictureBox1.Image == videoPictureBox1.ErrorImage)
        {
            cam.Stop(); //ALSO NOT NECESSARY> AGAIN, JUST TRYING TO FIX THE BIG RED X!
            cam.Start();
        }
    }

我在if(videoPictureBox1.Image == videoPictureBox1.ErrorImage)上休息,即使大红色X上升,它也会评估为false,因为图像实际上是设置为位图。所以cam.Stop()和cam.Start()永远不会运行(不确定这是否会有所帮助,但我想我会尝试一下)。

videoPictureBox1.Refresh()每次都在运行,但同样 - 它没有任何区别。仍有大红色X.

正如我之前所说:如果我开始播放视频并且什么都不触摸,那么大红色X将永远不会发生。但是当我开始更改组合框或者拖动表单本身时,大红色X的几率呈指数上升。有时我可以在它发生之前翻阅组合框10-12次,有时它会在第二次点击组合框时发生。 : - \

任何人都可以解释这里发生的事情,也许可以提出一个关于修复它的最佳方法的建议吗?我还是很新的线程,所以我一直在努力解决这里发生的事情以及解决问题的最佳方法!任何朝着正确方向的推动都将是一个巨大的帮助!

4 个答案:

答案 0 :(得分:6)

最后,我在调用Handle_New_Frame中包装了一切。它永久地完全消除了大红色X问题。 > _>

private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs)
{
  this.Invoke((MethodInvoker)delegate
  {
    try
    {
        if (bitmap != null)
        {
            bitmap.Dispose(); //Without this, memory goes nuts
        }

        bitmap = new Bitmap(eventArgs.Frame);
    }
    catch { }

    //Draw some stuff on the images
    bitmap = AdjustBrightness(bitmap, brightnessMeter);
    bitmap = ApplyContrast(contrastMeter, bitmap);
    bitmap = Draw_Top_Line(bitmap);
    bitmap = Draw_Bottom_Line(bitmap);

    //Set the image into the picturebox
    this.Invoke((MethodInvoker)delegate
    {
        videoPictureBox1.Image = bitmap;
        frameRate++; //Keep track of the frame rate
    });

    GC.Collect(); //Without this, memory goes nuts
  });
}

答案 1 :(得分:3)

肖恩·哈格里夫斯(Shawn Hargreaves)有一个非常简洁的writeup“大红色的厄运X”。我发现在处理WinForm组件突然显示红色“X”的一般情况下,它非常有用。

总结:

  • 这是由控件从OnPaint事件中抛出异常引起的。
  • 一旦抛出,该控件将继续显示红色X并跳过触发OnPaint.
  • 要进行调试,请将调试器设置为捕获公共语言运行时异常,然后执行通常所做的任何操作以获取红色X.调试器将在发生的位置停止,允许您进行调查并希望找到一种方法防止它。

答案 2 :(得分:1)

尝试在使用位图的地方使用克隆。 的实施例

videoPictureBox1.Image = (Bitmap)bitmap.Clone();

答案 3 :(得分:0)

总而言之,这是一个经过测试的最低限度,即使在调整大小,启动,停止或改变分辨率时也不会显示红叉。

   public partial class PictureBoxVideo : Form
   {
      public PictureBoxVideo()
      {
         InitializeComponent();
         var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
         var videoSource = new VideoCaptureDevice(videoDevices[0].MonikerString);
         videoSource.NewFrame += Handle_Very_New_Frame;
         videoSource.Start();
      }

      private void Handle_Very_New_Frame(object sender, NewFrameEventArgs eventArgs)
      {
         this.Invoke((MethodInvoker)delegate {
            pictureBox.Image = new Bitmap(eventArgs.Frame);
         });
      }
   }

请注意,我们称之为videoSource.Start();从GUI-(创建)-thread,但从视频(工作者)线程调用回调处理程序(Handle_Very_New_Frame)。

我认为这就是为什么我们需要Invoke和新的Bitmap,所以新的bmp也将从gui-thread生成。但我只是在这里猜测,因为我无法提出证据。