如何根据嵌套循环中的多个变量报告进度(对于进度条)?
How can I report progress based on multiple variables in a nested loop (for a progress bar)?
我有一个 BackgroundWorker 和一个 ProgressBar。工作时,BackgroundWorker 运行 通过三重 for 循环向 ProgressBar 报告进度。
目前,报告的进度仅是最外层循环 (xProgress) 的进度,该循环有效,但运行 并不顺利。目的是让ProgressBar也能计算内循环的进度百分比,让ProgressBar更新更流畅更准确。
DoWork 方法:
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
int xMax, yMax, zMax;
xMax = 10;
for (int x = 1; x <= xMax; x++)
{
yMax = 5;
for (int y = 1; y <= yMax; y++)
{
zMax = new Random().Next(50, 100);
for (int z = 1; z <= zMax; z++)
{
Thread.Sleep(5); /// The process
double xProgress = (double)x / (double)xMax;
double yProgress = (double)y / (double)yMax;
double zProgress = (double)z / (double)zMax;
/// The progress calculation:
double progressCalc = xProgress;
int progress = (int)(progressCalc * pgb.Maximum);
bgw.ReportProgress(progress);
}
}
}
}
更新答案:
由于内部循环的迭代次数未知,您可以决定它应该前进多少步。例如 10.
那么你可以这样做:
progressbarMaximum = xMax * yMax * 10
就在 z-loop 之前,您通过将 zMax 除以 10 得到 zModulo。
在你的 z-loop 中检查是否
zMax % zModulo == 0
然后增加进度条。
旧答案:
如果将 xMax、yMax 和 zMax 相乘,您将得到最内层循环的总迭代次数。
将进度条最大值设置为该值。
在内循环增量进度条的每次迭代中。
你不能让它准确。这样想——如果第一个随机数都是 50,而你已经完成了 2 个外部循环的一半——如果其余的随机数是 50——你已经完成了 50%。如果其余的随机数是 100 - 你只会完成 33%。所以你不知道进度条应该多远
(当然随机结果一般不会这样,只是为了说明问题。)
即使您事先不知道您的 best/worst 案例,这仍然有效。
任何最大值都可以按照 zMax
.
的相同方式随机化
static void F()
{
var r = new Random();
int xMax = 10;
int yMax = 5;
int zMax;
for (int x = 0; x < xMax; x++)
{
double xProg = (double)x / xMax;
for (int y = 0; y < yMax; y++)
{
double yProg = (double)y / (yMax * xMax);
zMax = r.Next(50, 100);
for (int z = 0; z < zMax; z++)
{
double zProg = (double)z / (zMax * yMax * xMax);
var prog = xProg + yProg + zProg;
Console.WriteLine(prog.ToString("P"));
// bgw.ReportProgress((int)(prog * pgb.Maximum));
}
}
}
Console.WriteLine(1.ToString("P")); // Make sure to report the final 100%
// bgw.ReportProgress((int)pgb.Maximum);
}
顺便说一句,我会将 pgb.Maximum
替换为 1
,然后在 OnProgressHandler
中将进度乘以它。这样,线程方法根本不会触及 UI 个元素。
的确,您无法确切知道循环将执行多少次迭代,但您肯定可以平滑进度指示器。
假设最坏情况下的总迭代次数是 xMax * yMax * worstZMax。
worstZMax = 99 因为上限在 Random.Next(minValue:int, maxValue:int)
中是唯一的
因此最坏情况下的总迭代次数将为 5 * 10 * 99 = 4950
。
现在我们可以从总数开始,并在为每个 y 循环生成 zMax 后放松迭代时根据需要调整它,我们将有效地平滑进度计算和报告。
我会这样做:
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
const int xMax = 10;
const int yMax = 5;
const int worstZMax = 99; //because upper is exclusive in Random.Next(lower, upper)
var iteration = 0;
var total = xMax * yMax * worstZMax; //total number of iterations (worst case)
for (var x = 1; x <= xMax; x++)
{
for (var y = 1; y <= yMax; y++)
{
var zMax = new Random().Next(50, 100);
//get how many iterations did we miss, and adjust the total iterations
total -= worstZMax - zMax;
for (var z = 1; z <= zMax; z++)
{
iteration++; //count this iteration
Thread.Sleep(5); // The process
// The progress calculation
var progress = (double)iteration / total * pgb.Maximum;
bgw.ReportProgress((int)progress);
}
}
}
}
希望对您有所帮助!
我有一个 BackgroundWorker 和一个 ProgressBar。工作时,BackgroundWorker 运行 通过三重 for 循环向 ProgressBar 报告进度。
目前,报告的进度仅是最外层循环 (xProgress) 的进度,该循环有效,但运行 并不顺利。目的是让ProgressBar也能计算内循环的进度百分比,让ProgressBar更新更流畅更准确。
DoWork 方法:
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
int xMax, yMax, zMax;
xMax = 10;
for (int x = 1; x <= xMax; x++)
{
yMax = 5;
for (int y = 1; y <= yMax; y++)
{
zMax = new Random().Next(50, 100);
for (int z = 1; z <= zMax; z++)
{
Thread.Sleep(5); /// The process
double xProgress = (double)x / (double)xMax;
double yProgress = (double)y / (double)yMax;
double zProgress = (double)z / (double)zMax;
/// The progress calculation:
double progressCalc = xProgress;
int progress = (int)(progressCalc * pgb.Maximum);
bgw.ReportProgress(progress);
}
}
}
}
更新答案:
由于内部循环的迭代次数未知,您可以决定它应该前进多少步。例如 10.
那么你可以这样做:
progressbarMaximum = xMax * yMax * 10
就在 z-loop 之前,您通过将 zMax 除以 10 得到 zModulo。 在你的 z-loop 中检查是否
zMax % zModulo == 0
然后增加进度条。
旧答案:
如果将 xMax、yMax 和 zMax 相乘,您将得到最内层循环的总迭代次数。
将进度条最大值设置为该值。
在内循环增量进度条的每次迭代中。
你不能让它准确。这样想——如果第一个随机数都是 50,而你已经完成了 2 个外部循环的一半——如果其余的随机数是 50——你已经完成了 50%。如果其余的随机数是 100 - 你只会完成 33%。所以你不知道进度条应该多远
(当然随机结果一般不会这样,只是为了说明问题。)
即使您事先不知道您的 best/worst 案例,这仍然有效。
任何最大值都可以按照 zMax
.
static void F()
{
var r = new Random();
int xMax = 10;
int yMax = 5;
int zMax;
for (int x = 0; x < xMax; x++)
{
double xProg = (double)x / xMax;
for (int y = 0; y < yMax; y++)
{
double yProg = (double)y / (yMax * xMax);
zMax = r.Next(50, 100);
for (int z = 0; z < zMax; z++)
{
double zProg = (double)z / (zMax * yMax * xMax);
var prog = xProg + yProg + zProg;
Console.WriteLine(prog.ToString("P"));
// bgw.ReportProgress((int)(prog * pgb.Maximum));
}
}
}
Console.WriteLine(1.ToString("P")); // Make sure to report the final 100%
// bgw.ReportProgress((int)pgb.Maximum);
}
顺便说一句,我会将 pgb.Maximum
替换为 1
,然后在 OnProgressHandler
中将进度乘以它。这样,线程方法根本不会触及 UI 个元素。
的确,您无法确切知道循环将执行多少次迭代,但您肯定可以平滑进度指示器。
假设最坏情况下的总迭代次数是 xMax * yMax * worstZMax。
worstZMax = 99 因为上限在 Random.Next(minValue:int, maxValue:int)
因此最坏情况下的总迭代次数将为 5 * 10 * 99 = 4950
。
现在我们可以从总数开始,并在为每个 y 循环生成 zMax 后放松迭代时根据需要调整它,我们将有效地平滑进度计算和报告。
我会这样做:
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
const int xMax = 10;
const int yMax = 5;
const int worstZMax = 99; //because upper is exclusive in Random.Next(lower, upper)
var iteration = 0;
var total = xMax * yMax * worstZMax; //total number of iterations (worst case)
for (var x = 1; x <= xMax; x++)
{
for (var y = 1; y <= yMax; y++)
{
var zMax = new Random().Next(50, 100);
//get how many iterations did we miss, and adjust the total iterations
total -= worstZMax - zMax;
for (var z = 1; z <= zMax; z++)
{
iteration++; //count this iteration
Thread.Sleep(5); // The process
// The progress calculation
var progress = (double)iteration / total * pgb.Maximum;
bgw.ReportProgress((int)progress);
}
}
}
}
希望对您有所帮助!