后台工作人员正在进行时无法移动主窗体
Main form can't be moved while Background Worker in progress
我正在 Windows 表单中编写一个简单的图片混合器。虽然它工作得很好,但我有一个问题 - 当应用程序正在进行时 - 我无法移动主要的 Winodow 窗体。该应用程序允许两个线程在后台工作。当只有一个忙时,如果我尝试拖动 window 它会延迟响应(好像它需要时间才能重新获得焦点)。当两个 Background Builders 完成他们的任务时,我根本无法移动主窗体。他们完成后,我可以再次移动 window。
我认为将 '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;
}
为了扩展@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
将有助于提高实际性能。由于这部分是它自己的主题,而且我不太熟悉,所以我只提供一些可能有助于您入门的链接:
How do I conver my get GetPixel/SetPixel color processing to Lockbits
另一种方法:
Faster Alternatives to SetPixel and GetPixel for Bitmaps for Windows Forms App
我正在 Windows 表单中编写一个简单的图片混合器。虽然它工作得很好,但我有一个问题 - 当应用程序正在进行时 - 我无法移动主要的 Winodow 窗体。该应用程序允许两个线程在后台工作。当只有一个忙时,如果我尝试拖动 window 它会延迟响应(好像它需要时间才能重新获得焦点)。当两个 Background Builders 完成他们的任务时,我根本无法移动主窗体。他们完成后,我可以再次移动 window。 我认为将 '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;
}
为了扩展@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
将有助于提高实际性能。由于这部分是它自己的主题,而且我不太熟悉,所以我只提供一些可能有助于您入门的链接:
How do I conver my get GetPixel/SetPixel color processing to Lockbits
另一种方法:
Faster Alternatives to SetPixel and GetPixel for Bitmaps for Windows Forms App