后台工作程序正在进行时无法移动主窗体(Main form can't be moved while Background Worker in progress)

编程入门 行业动态 更新时间:2024-10-24 07:26:19
后台工作程序正在进行时无法移动主窗体(Main form can't be moved while Background Worker in progress)

我正在Windows窗体中编写一个简单的图片混合器。 虽然它工作得相当好我有一个问题 - 在应用程序正在进行中 - 我无法移动主Winodow表单。 该应用程序允许两个线程在后台工作。 当只有一个人忙时,如果我试图拖动窗口,它会延迟响应(好像需要时间来获得焦点)。 当两个背景建造者完成他们的任务时,我根本无法移动主要形式。 完成后我可以再次移动窗口。 我认为将'this'作为参数传递给另一个线程可能是问题所在,但是我复制了我需要的字段,以防我在调用单独的线程后添加'this.Activate()'。 无论如何,这没有任何区别。

这就是我打电话给工人的方式:

private void PerformBlending() { if (!bw2.IsBusy) { bw2.RunWorkerAsync(this); this.Activate(); } else { bw3.RunWorkerAsync(this); this.Activate(); } } private void bw2_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker bw = sender as BackgroundWorker; Form1 mainForm = e.Argument as Form1; Bitmap leftBmp = new Bitmap(mainForm.buttonPic1.BackgroundImage); Bitmap rightBmp = new Bitmap(mainForm.buttonPic2.BackgroundImage); Bitmap resultBmp; int leftX = leftBmp.Width; int leftY = leftBmp.Height; int rightX = rightBmp.Width; int rightY = rightBmp.Height; int x = leftX < rightX ? leftX : rightX; int y = leftY < rightY ? leftY : rightY; resultBmp = new Bitmap(x, y); double alfa = mainForm.trackBarValue; for (int i = 0; i < x; ++i) //Parallel.For(0, x, i => { for (int j = 0; j < y; ++j) { bw.ReportProgress((int)(((double)i / (double)y + (double)1 / (double)x) * 100)); int leftR = (i < leftX && j < leftY) ? (int)(alfa * leftBmp.GetPixel(i, j).R) : 0; int leftG = (i < leftX && j < leftY) ? (int)(alfa * leftBmp.GetPixel(i, j).G) : 0; int leftB = (i < leftX && j < leftY) ? (int)(alfa * leftBmp.GetPixel(i, j).B) : 0; int rightR = (i < rightX && j < rightY) ? (int)((1 - alfa) * rightBmp.GetPixel(i, j).R) : 0; int rightG = (i < rightX && j < rightY) ? (int)((1 - alfa) * rightBmp.GetPixel(i, j).G) : 0; int rightB = (i < rightX && j < rightY) ? (int)((1 - alfa) * rightBmp.GetPixel(i, j).B) : 0; int r = leftR + rightR; int g = leftG + rightG; int b = leftB + rightB; resultBmp.SetPixel(i, j, Color.FromArgb(r, g, b)); } }//); e.Result = resultBmp; }

I am writing a simple picture blender in Windows Forms. Although it works rather fine I have a problem - while application is in progress - I can't move the main Winodow Form. The application allows two threads to work in background. When only one is busy then if I try to drag the window it responds with a delay (as if it needed time to get a focus back). When two Background Builders do their task I can't move main form at all. After they finish I can move window again. I thought that passing 'this' as a argument to another thread might be the issue, but I make copies of fields I need and just in case I've added 'this.Activate()' after calling a separate thread. This makes no difference anyway.

This is how I call workers:

private void PerformBlending() { if (!bw2.IsBusy) { bw2.RunWorkerAsync(this); this.Activate(); } else { bw3.RunWorkerAsync(this); this.Activate(); } } private void bw2_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker bw = sender as BackgroundWorker; Form1 mainForm = e.Argument as Form1; Bitmap leftBmp = new Bitmap(mainForm.buttonPic1.BackgroundImage); Bitmap rightBmp = new Bitmap(mainForm.buttonPic2.BackgroundImage); Bitmap resultBmp; int leftX = leftBmp.Width; int leftY = leftBmp.Height; int rightX = rightBmp.Width; int rightY = rightBmp.Height; int x = leftX < rightX ? leftX : rightX; int y = leftY < rightY ? leftY : rightY; resultBmp = new Bitmap(x, y); double alfa = mainForm.trackBarValue; for (int i = 0; i < x; ++i) //Parallel.For(0, x, i => { for (int j = 0; j < y; ++j) { bw.ReportProgress((int)(((double)i / (double)y + (double)1 / (double)x) * 100)); int leftR = (i < leftX && j < leftY) ? (int)(alfa * leftBmp.GetPixel(i, j).R) : 0; int leftG = (i < leftX && j < leftY) ? (int)(alfa * leftBmp.GetPixel(i, j).G) : 0; int leftB = (i < leftX && j < leftY) ? (int)(alfa * leftBmp.GetPixel(i, j).B) : 0; int rightR = (i < rightX && j < rightY) ? (int)((1 - alfa) * rightBmp.GetPixel(i, j).R) : 0; int rightG = (i < rightX && j < rightY) ? (int)((1 - alfa) * rightBmp.GetPixel(i, j).G) : 0; int rightB = (i < rightX && j < rightY) ? (int)((1 - alfa) * rightBmp.GetPixel(i, j).B) : 0; int r = leftR + rightR; int g = leftG + rightG; int b = leftB + rightB; resultBmp.SetPixel(i, j, Color.FromArgb(r, g, b)); } }//); e.Result = resultBmp; }

最满意答案

要扩展@ LarsTech的注释,您当前的进度计算甚至不依赖于j因此将ReportProgress调用移到内部循环之外。 这将通过减少调用次数来帮助响应,甚至不会改变ProgressBar的行为。

for (int i = 0; i < x; ++i) //Parallel.For(0, x, i => { bw.ReportProgress((int)(((double)i / (double)y + (double)1 / (double)x) * 100)); for (int j = 0; j < y; ++j) { int leftR = (i < leftX && j < leftY) ? (int)(alfa * leftBmp.GetPixel(i, j).R) : 0; int leftG = (i < leftX && j < leftY) ? (int)(alfa * leftBmp.GetPixel(i, j).G) : 0; int leftB = (i < leftX && j < leftY) ? (int)(alfa * leftBmp.GetPixel(i, j).B) : 0; int rightR = (i < rightX && j < rightY) ? (int)((1 - alfa) * rightBmp.GetPixel(i, j).R) : 0; int rightG = (i < rightX && j < rightY) ? (int)((1 - alfa) * rightBmp.GetPixel(i, j).G) : 0; int rightB = (i < rightX && j < rightY) ? (int)((1 - alfa) * rightBmp.GetPixel(i, j).B) : 0; int r = leftR + rightR; int g = leftG + rightG; int b = leftB + rightB; resultBmp.SetPixel(i, j, Color.FromArgb(r, g, b)); } }//);

此外,使用LockBits将有助于实际性能。 由于这部分是它自己的主题,而且我不太熟悉,我只是给出一些可能有助于你开始的链接:

LockBits与获取/设置像素

如何将获取的GetPixel / SetPixel颜色处理转换为Lockbits

对于不同的方法:

用于Windows窗体应用程序的BitPps的SetPixel和GetPixel的更快替代品

To expand on @LarsTech's comment, your current progress calculation isn't even dependent on j so move the ReportProgress call outside of the inner loop. This will help responsiveness by reducing the number of calls without even changing the behavior of your ProgressBar.

for (int i = 0; i < x; ++i) //Parallel.For(0, x, i => { bw.ReportProgress((int)(((double)i / (double)y + (double)1 / (double)x) * 100)); for (int j = 0; j < y; ++j) { int leftR = (i < leftX && j < leftY) ? (int)(alfa * leftBmp.GetPixel(i, j).R) : 0; int leftG = (i < leftX && j < leftY) ? (int)(alfa * leftBmp.GetPixel(i, j).G) : 0; int leftB = (i < leftX && j < leftY) ? (int)(alfa * leftBmp.GetPixel(i, j).B) : 0; int rightR = (i < rightX && j < rightY) ? (int)((1 - alfa) * rightBmp.GetPixel(i, j).R) : 0; int rightG = (i < rightX && j < rightY) ? (int)((1 - alfa) * rightBmp.GetPixel(i, j).G) : 0; int rightB = (i < rightX && j < rightY) ? (int)((1 - alfa) * rightBmp.GetPixel(i, j).B) : 0; int r = leftR + rightR; int g = leftG + rightG; int b = leftB + rightB; resultBmp.SetPixel(i, j, Color.FromArgb(r, g, b)); } }//);

Also, using LockBits will help with actual performance. As this part is kind of its own topic and one I'm not too familiar with, I'll just give some links that might help you get started:

LockBits vs Get/Set Pixel

How do I conver my get GetPixel/SetPixel color processing to Lockbits

And for a different approach:

Faster Alternatives to SetPixel and GetPixel for Bitmaps for Windows Forms App

更多推荐

本文发布于:2023-08-02 18:02:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1380684.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:窗体   正在进行   后台   程序   工作

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!