C# Picturebox变大了,但我可以';无法检测或修复它
我目前正在使用AForge,并且有一个关于新帧的事件,该事件将帧作为位图发布到picturebox中。90%的时间它工作得很好。。。除非我在winform上摆弄什么东西。更改组合框、移动窗口或诸如此类的操作可能会导致Picturebox从视频切换到一个大的红色X。下面的代码示例:C# Picturebox变大了,但我可以';无法检测或修复它,c#,winforms,thread-safety,picturebox,aforge,C#,Winforms,Thread Safety,Picturebox,Aforge,我目前正在使用AForge,并且有一个关于新帧的事件,该事件将帧作为位图发布到picturebox中。90%的时间它工作得很好。。。除非我在winform上摆弄什么东西。更改组合框、移动窗口或诸如此类的操作可能会导致Picturebox从视频切换到一个大的红色X。下面的代码示例: private void connectButton_Click(object sender, EventArgs e) { try { cam
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)上加了一个中断,它的计算结果为false,即使在红色大X出现时也是如此,因为图像实际上被设置为位图。所以cam.Stop()和cam.Start()永远不会运行(不确定这是否有用,但我想我会尝试一下)
videoPictureBox1.Refresh()每次都在运行,但同样,这并没有什么不同。还有红色的大X
正如我之前所说:如果我启动视频,什么都不碰,那么红色的大X永远不会发生。但当我开始改变组合框,或者拖动表单本身时,出现红色大X的几率呈指数增长。有时,我可以在组合框出现之前将其翻转10-12次,其他情况下,在我单击组合框时,它就会出现。:-\
有人能解释一下这里发生了什么,也许能提供一个关于解决问题的最佳方法的建议吗?我还是一个线程新手,所以我一直在努力思考这里到底发生了什么,以及解决这个问题的最佳方法!任何朝正确方向的轻推都将是巨大的帮助 在使用位图的位置尝试使用克隆。 Ex:
videoPictureBox1.Image = (Bitmap)bitmap.Clone();
最后,我将所有内容包装在调用的Handle\u New\u框架中。它彻底地永久性地消除了大红色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
});
}
肖恩·哈格里夫斯(Shawn Hargreaves)的《末日的大红色X》(big red X of doom)一书精妙、简洁。我发现它在处理WinForm组件突然显示红色“X”的一般情况下非常有用 总之:
- 这是由控件在
事件中抛出异常引起的OnPaint
- 一旦抛出该控件,该控件将继续显示红色X,并跳过在绘制时触发。
- 要进行调试,请将调试器设置为捕获公共语言运行时异常,然后执行您通常执行的任何操作以获取红色X。调试器将在发生错误的地方停止,从而允许您进行调查,并希望找到防止错误发生的方法
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-(创建)-线程,但回调处理程序(Handle_Very_New_Frame)是从视频(worker)线程调用的
我认为这就是为什么我们需要调用和新位图,因此新的bmp也将从gui线程生成。但我只是在猜测,因为我找不到证据。我想我可能只是不使用图片框。改为使用面板,并在面板的绘制事件中绘制位图。使用invalidate强制刷新。在大红色X senario期间,您看过eventArgs.Frame吗?另外,我会在异常下放置一个messagebox,以防出现错误。好的,我会很快尝试一下!另一个注意事项:我转到debug->exceptions并选中了所有“抛出”复选框。当这种情况发生时,什么也不会发生。好的,金戴夫,我现在也要试试!谢谢我添加了一个面板,将“videoPictureBox1.Image=bitmap”更改为“panel3.BackGroundImage=bitmap;panel3.Invalidate();”。移动表单时,我再次得到了红色的大X:(我还在那个catch中添加了一条消息-它从来没有被调用过!这是我引入的一个令人困惑的小错误!如果修复它就像创建它一样简单,那就好了!lol!这也可能会导致竞争条件,或者我错了吗?如果在处理位图和克隆位图之间发生重画,那么会出现红色的大X。@Hans是的,尝试使用位图处置前@Hans,你能检查一下我答案中的代码吗?我试图生成这样一个竞争条件,但没有成功。我遇到了完全相同的事情,也试图弄清楚发生了什么,但没有结果。我猜这是一些单线程策略,但我没有得到任何异常或错误消息,我采用了你的方法,现在它工作了.hi,我使用了它,但当我尝试关闭videoSource时,它不会停止并等待释放资源…您是否遇到了相同的问题?关于您对GC.Collect()的评论。位图的继承链实现了IDisposable。GC问题可能是由于您缺少调用Dispose。请尝试使用块或手动调用Bitmap.Dispose().BTW:我很快就放弃了这种方法,原因很明显:-)嗨,我用过它,但当我试图关闭videoSource时,它不会停下来等待释放资源…你有同样的问题吗?链接断了。更新的链接:@TobiasKnauss谢谢!我在答案中更新了链接。