Windows 7 Windows7 Aero主题进度条错误? 我碰到了我认为是Windows 7上的进度条错误。为了演示这个bug,我创建了一个带有按钮和进度条的WinForm应用程序。在按钮的“点击”手柄中,我有以下代码 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"; } private void按钮单击(对象发送者,事件参数e) { 此.progressBar.Minimum=0; 此.progressBar.最大值=100; this.buttonGo.Text=“忙”; this.buttonGo.Update(); 对于(inti=0;i
我在Vista和Windows7上看到了类似的进度条问题 我的例子中的关键问题是UI线程阻塞(就像您在示例中所做的那样) Windows不喜欢不响应消息队列中新消息的应用程序。如果您在一条消息上花费太多时间,Windows会将您的应用程序标记为“无响应”。在Vista/Win7中,Windows还会决定停止更新您的应用程序窗口 作为一种解决方法,您可以将实际工作放在后台工作人员身上,或者每隔一段时间调用Windows 7 Windows7 Aero主题进度条错误? 我碰到了我认为是Windows 7上的进度条错误。为了演示这个bug,我创建了一个带有按钮和进度条的WinForm应用程序。在按钮的“点击”手柄中,我有以下代码 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"; } private void按钮单击(对象发送者,事件参数e) { 此.progressBar.Minimum=0; 此.progressBar.最大值=100; this.buttonGo.Text=“忙”; this.buttonGo.Update(); 对于(inti=0;i,windows-7,progress-bar,aero,Windows 7,Progress Bar,Aero,我在Vista和Windows7上看到了类似的进度条问题 我的例子中的关键问题是UI线程阻塞(就像您在示例中所做的那样) Windows不喜欢不响应消息队列中新消息的应用程序。如果您在一条消息上花费太多时间,Windows会将您的应用程序标记为“无响应”。在Vista/Win7中,Windows还会决定停止更新您的应用程序窗口 作为一种解决方法,您可以将实际工作放在后台工作人员身上,或者每隔一段时间调用Application.DoEvents()。您确实需要确保进度条窗口是模态的,否则DoEve
Application.DoEvents()
。您确实需要确保进度条窗口是模态的,否则DoEvents()可能会使新命令在后台处理的中途开始执行
如果这让人觉得很尴尬,更合适的方法是在
BackgroundWorker
线程上进行后台工作。它支持将事件发送到UI线程以更新进度条。我在Vista和Windows 7上看到过类似的进度条问题
我的例子中的关键问题是UI线程阻塞(就像您在示例中所做的那样)
Windows不喜欢不响应消息队列中新消息的应用程序。如果您在一条消息上花费太多时间,Windows会将您的应用程序标记为“无响应”。在Vista/Win7中,Windows还会决定停止更新您的应用程序窗口
作为一种解决方法,您可以将实际工作放在后台工作人员身上,或者每隔一段时间调用Application.DoEvents()
。您确实需要确保进度条窗口是模态的,否则DoEvents()可能会使新命令在后台处理的中途开始执行
如果这让人觉得很尴尬,更合适的方法是在
BackgroundWorker
线程上进行后台工作。它支持向UI线程发送事件以更新进度条。我认为最初的问题与进度条的计时和Win7(或Aero)动画机制有关
此子项位于包含进度条(pBar)的表单上
它改变了条的最大值,并将条的最大值固定为10,完成百分比为1到99。条的最小值在设计时设置为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
Public Sub-UpdateStatusPC(ByVal pc作为整数)
尝试
如果pc<0,则
pBar.最大值=100
pBar.Value=0
如果pc>100,则
pBar.最大值=100
pBar.值=100
ElseIf pc=0,则
pBar.最大值=10
pBar.Value=0
其他的
pBar.值=10
pBar最大值=10/CDbl(pc/100.0)
如果结束
pBar.Update()
特例
MsgBox(“UpdateStatusPC:&ex.Message”)
结束尝试
端接头
我认为最初的问题与进度条的计时和Win7(或Aero)动画机制有关
此子项位于包含进度条(pBar)的表单上
它改变了条的最大值,并将条的最大值固定为10,完成百分比为1到99。条的最小值在设计时设置为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
Public Sub-UpdateStatusPC(ByVal pc作为整数)
尝试
如果pc<0,则
pBar.最大值=100
pBar.Value=0
如果pc>100,则
pBar.最大值=100
pBar.值=100
ElseIf pc=0,则
pBar.最大值=10
pBar.Value=0
其他的
pBar.值=10
pBar最大值=10/CDbl(pc/100.0)
如果结束
pBar.Update()
特例
MsgBox(“UpdateStatusPC:&ex.Message”)
结束尝试
端接头
这与进度条的动画有关。如果进度条为0%,而您将其设置为100%,则它不会跳到那里,而是将进度条平滑填充。如果速度太慢,您将在进度条完成动画制作之前完成。因此,即使您已将其设置为80%、90%和100%,动画仍将继续仍然落后
我从未找到关闭此功能的方法,但是我有一个解决方法。只有当你增加进度条时,动画才会完成。如果你向后移动它,它会立即跳到该位置。因此,如果我希望进度条位于x%(x!=100),则我将其移动到x+1,然后移动到x。如果我希望进度条位于100%,则将其移动到100%、99%和100%。(或者不管你使用什么值,你都会明白的。)这工作速度足够快,以至于看不见,你也可以在以前的Windows版本中保留这段代码(尽管我没有).这与进度条的动画有关。如果进度条为0%,而您将其设置为100%,则它将不会跳到那里,而是将进度条平滑填充。如果速度太慢,您将在进度条完成动画制作之前完成。因此,即使您已将其设置为80%、90%和100%,动画仍将继续直到落后 我从未找到关闭此功能的方法,但是我有一个解决方法。只有当你增加进度条时,动画才会完成。如果你向后移动它,它会立即跳到该位置。因此,如果我希望进度条位于x%(x!=100),则我将其移动到x+1,然后移动到x。如果我希望进度条位于100%,则将其移动到100%、99%和100%。(或者,不管你使用什么值,你都能理解。)这项技术的工作速度足够快,以至于看不见
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.
if Abs(FOriginalMax - value) <= 1 then
pct := HUNDO
:
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.
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.