我遇到了我认为是Windows 7上的进度条错误。为了演示该错误,我创建了一个带有按钮和进度条的WinForm应用程序。在按钮的'on-click'句柄中,我有以下代码。
private void buttonGo_Click(object sender, EventArgs e)
{
this.progressBar.Minimum = 0;
this.progressBar.Maximum = 100;
this.buttonGo.Text = "Busy";
this.buttonGo.Update();
for (int i = 0; i <= 100; ++i)
{
this.progressBar.Value = i;
this.Update();
System.Threading.Thread.Sleep(10);
}
this.buttonGo.Text = "Ready";
}
预期的行为是进度条前进到100%,然后按钮文本更改为“就绪”。但是,在Windows 7上开发此代码时,我注意到进度条将上升到大约75%,然后按钮文本将变为“就绪”。假设代码是同步的,这不应该发生!
在进一步测试中,我发现在Windows Server 2003上运行的完全相同的代码产生了预期的结果。此外,在Windows 7上选择非航空主题会产生预期的结果。
在我看来,这似乎是个错误。通常,当长操作涉及复杂的代码时,很难使进度条准确,但在我的特定情况下,它非常直接,所以当我发现进度控制没有准确地表示进度时,我感到很失望。
还有其他人注意到这种行为吗?有人找到了解决方法吗?
答案 0 :(得分:18)
它与进度条的动画有关。如果您的进度条为0%并且您将其设置为100%,那么它将不会跳到那里,但会使进度条平滑填充动画。如果这太慢,您将在进度条完成动画之前完成。因此即使你已经将其设置为80%,90%和100%,动画仍然落后。
我从来没有找到办法解决此问题,但我有一个解决方法。只有在增加进度条时才会执行动画。如果向后移动,它会立即跳到该位置。因此,如果我希望进度条位于x%(x!= 100),那么我将其移至x + 1然后移至x。如果我想要它100%,我将它移动到100%,99%和100%。 (或者无论你使用什么值,你都可以得到这个想法。)这个工作得足够快,不会被看到,你也可以将此代码留给以前的Windows版本(尽管我没有)。
答案 1 :(得分:4)
我遇到了同样的问题。 Fozi的tipp帮助了我。在设置新值之前,我已将值设置为1.要使此工作也为100%,必须先增加最大值。以下对我来说很好。
if (NewValue < progressBar.Maximum)
{
progressBar.Value = NewValue + 1;
progressBar.Value--;
}
else
{
progressBar.Maximum++;
progressBar.Value = progressBar.Maximum;
progressBar.Value--;
progressBar.Maximum--;
}
答案 2 :(得分:3)
我认为最初的问题与进度条的计时和Win7(或Aero的)动画机制有关。
此Sub位于包含进度条(pBar)的表单上。
它改变了条的.Maximum并保持.Value固定为10,完成百分比为1到99.条形码.Minimum在设计时设置为0。
这为我解决了这个问题。
Public Sub UpdateStatusPC(ByVal pc As Integer)
Try
If pc < 0 Then
pBar.Maximum = 100
pBar.Value = 0
ElseIf pc > 100 Then
pBar.Maximum = 100
pBar.Value = 100
ElseIf pc = 0 Then
pBar.Maximum = 10
pBar.Value = 0
Else
pBar.Value = 10
pBar.Maximum = 10 / CDbl(pc / 100.0)
End If
pBar.Update()
Catch ex As Exception
MsgBox("UpdateStatusPC: " & ex.Message)
End Try
End Sub
答案 3 :(得分:2)
unit ProgressBarFix;
(* The standard progress bar fails under Windows theming -- it fails to animate
all the way to the right side. C.f.,
http://stackoverflow.com/questions/2217688/windows-7-aero-theme-progress-bar-bug
To work around the problem, include ProgressBarFix in the interface section's
"uses" clause *after* ComCtrls (this replaces the TProgressBar definition in
ConCtrls with the one here, effectively allowing the control defined on the
form to be replaced with the patch version.
c.f., http://www.deltics.co.nz/blog/?p=222and http://melander.dk/articles/splitter *)
interface
uses ComCtrls ;
type TProgressBar = class(ComCtrls.TProgressBar)
private
procedure SetPosition(Value: Integer);
function GetPosition: Integer;
published
property Position: Integer read GetPosition write SetPosition default 0;
end ;
implementation
{ TProgressBar }
function TProgressBar.GetPosition: Integer;
begin
result := inherited Position
end;
procedure TProgressBar.SetPosition(Value: Integer);
begin
if Value=inherited Position then
exit ;
if value<Max then begin
inherited Position := value+1 ;
inherited Position := value
end else begin
Max := Max+1 ;
inherited Position := Max ;
inherited Position := value ;
Max := Max-1
end
end;
end.
答案 4 :(得分:1)
在“效果选项”中禁用视觉效果选项“动画窗口内的控件和元素”。然后,进度条将不再动画。
答案 5 :(得分:0)
我在Vista和Windows 7上看到了与进度条类似的问题。
我的案例中的关键问题是阻止了UI线程。 (就像你在样本中所做的那样)。
Windows不喜欢不响应消息队列中的新消息的应用程序。如果您在一条消息上花费太多时间,Windows会将您的应用程序标记为“无响应”。在Vista / Win7中,Windows还决定停止更新您的应用程序窗口。
作为一种解决方法,您可以将实际工作放在后台工作人员上,或者每隔一段时间调用Application.DoEvents()
。您确实需要确保进度条窗口是模态的,否则DoEvents()可能会启用新命令以在后台处理中途开始执行。
如果感觉到kludgy,更恰当的方法是在BackgroundWorker
线程上进行后台工作。它支持将事件发送到UI线程以更新进度条。
答案 6 :(得分:0)
(09/2015)我刚刚从D6跳到了XE8。有很多问题。包括这个TProgressBar的东西。把它搁置一段时间。今晚遇到了这个问题(Erik Knowles)。太棒了。除外:我遇到的第一个场景的最大值为9,770,880。并且它(Erik Knowles的“原始”修复)真正添加到此过程所花费的时间(所有额外的实际更新ProgressBar)。
所以我扩展了他的课程以减少ProgressBar实际重绘的次数。但只有“原始”Max值大于MIN_TO_REWORK_PCTS(我在这里定居5000)。
如果是这样的话,ProgressBar只会更新自己的HUNDO次数(这里我开始使用并且几乎已经确定为100,因此是“HUNDO”名称)。
我在Max值上也有一些怪癖:
if Abs(FOriginalMax - value) <= 1 then
pct := HUNDO
我用最初的9.8m Max测试了这个。而且,使用这个独立的测试应用程序:
:
uses
:
ProgressBarFix;
const
PROGRESS_PTS = 500001;
type
TForm1 = class(TForm)
Label1: TLabel;
PB: TProgressBar;
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
x: integer;
begin
PB.Min := 0;
PB.Max := PROGRESS_PTS;
PB.Position := 0;
for x := 1 to PROGRESS_PTS do
begin
//let's do something
//
Label1.Caption := Format('%d of %d',[x,PROGRESS_PTS]);
Update;
PB.Position := x;
end;
PB.Position := 0;
end;
end.
,PROGRESS_PTS值为: 10 100 1000 万 100000 百万
所有这些值都很平滑,“准确” - 没有真正放慢任何速度。
在测试中,我能够切换我的编译器指令DEF_USE_MY_PROGRESS_BAR以测试两种方式(此TProgressBar替换与原始版本相比)。
请注意,您可能希望取消对Application.ProcessMessages的调用。
这是(我的“增强”)ProgressBarFix来源:
unit ProgressBarFix;
interface
uses
Vcl.ComCtrls;
type
TProgressBar = class(Vcl.ComCtrls.TProgressBar)
const
HUNDO = 100;
MIN_TO_REWORK_PCTS = 5000;
private
function GetMax: integer;
procedure SetMax(value: integer);
function GetPosition: integer;
procedure SetPosition(value: integer);
published
property Max: integer read GetMax write SetMax default 100;
property Position: integer read GetPosition write SetPosition default 0;
private
FReworkingPcts: boolean;
FOriginalMax: integer;
FLastPct: integer;
end;
implementation
function TProgressBar.GetMax: integer;
begin
result := inherited Max;
end;
procedure TProgressBar.SetMax(value: integer);
begin
FOriginalMax := value;
FLastPct := 0;
FReworkingPcts := FOriginalMax > MIN_TO_REWORK_PCTS;
if FReworkingPcts then
inherited Max := HUNDO
else
inherited Max := value;
end;
function TProgressBar.GetPosition: integer;
begin
result := inherited Position;
end;
procedure TProgressBar.SetPosition(value: integer);
var
pct: integer;
begin
//Application.ProcessMessages;
if value = inherited Position then
exit;
if FReworkingPcts then
begin
if Abs(FOriginalMax - value) <= 1 then
pct := HUNDO
else
pct := Trunc((value / FOriginalMax) * HUNDO);
if pct = FLastPct then
exit;
FLastPct := pct;
value := pct;
end;
if value < Max then
begin
inherited Position := Succ(value);
inherited Position := value;
end
else
begin
Max := Succ(Max);
inherited Position := Max;
inherited Position := value;
Max := Pred(Max);
end;
end;
end.