2017-08-03 55 views
0

在我使用的方法描述here放置在Delphi上TStatusBar一个TProgressBar过去:(?最近的Windows更新后)方法不再起作用

procedure TForm1.FormCreate(Sender: TObject); 
var 
    ProgressBarStyle: integer; 
begin 
    //enable status bar 2nd Panel custom drawing 
    StatusBar1.Panels[1].Style := psOwnerDraw; 
    //place the progress bar into the status bar 
    ProgressBar1.Parent := StatusBar1; 
    //remove progress bar border 
    ProgressBarStyle := GetWindowLong(ProgressBar1.Handle, GWL_EXSTYLE); 
    ProgressBarStyle := ProgressBarStyle - WS_EX_STATICEDGE; 
    SetWindowLong(ProgressBar1.Handle, GWL_EXSTYLE, ProgressBarStyle); 
end; 

procedure TForm1.StatusBar1DrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; 
    const Rect: TRect); 
begin 
    if Panel = StatusBar.Panels[1] then 
    with ProgressBar1 do 
    begin 
    Top := Rect.Top; 
    Left := Rect.Left; 
    Width := Rect.Right - Rect.Left; 
    Height := Rect.Bottom - Rect.Top; 
    end; 
end; 

但这不再有效,即旧方案仍按预期工作,但新编制的方案不会。我在Windows 10上使用了相同的Delphi版本XE8。

这是否意味着此方法不合适?什么是正确的方法来做到这一点?

+0

这是在上面创建一个窗口控件来显示这样的进展。我一直都是通过直接在面板中绘制进度来完成的。简单的FillRect调用,或者如果过程是风格化/主题化的,则使用风格/主题API。 –

+0

有道理,我会尝试。 (关于一般的进度条,不能这么说吗?)但是你不知道我的代码突然不再工作了吗?谢谢。 – stevenvh

回答

3

正如其他人所解释的,您对TProgressBar窗口样式的管理不当是造成您的问题的原因。

我想补充一点,你不需要使用(也不应该使用)TStatusBar.OnDrawPanel事件来定位TProgressBar。这是一个绘图事件,而不是对象管理事件。如果你不打算手动绘制进度条到TStatusBar.Canvas那么你应该完全摆脱OnDrawPanel处理程序。

可以代替定位TProgressBar一次启动时,通过使用SB_GETRECT消息访问面板的坐标和尺寸,然后相应地定位TProgressBar,如:

uses 
    CommCtrl; 

procedure TForm1.FormCreate(Sender: TObject); 
var 
    ... 
    R: TRect; 
begin 
    // no need to set the panel's Style to psOwnerDraw! 
    ... 
    //place the progress bar into the status bar 
    SendMessage(StatusBar1.Handle, SB_GETRECT, 1, LPARAM(@R)); 
    ProgressBar1.Parent := StatusBar1; 
    ProgressBar1.SetBounds(R.Left, R.Top, R.Width, R.Height); 
    ... 
end; 

如果你的表格是可调整大小,你可以使用TStatusBar.OnResize事件重新定位TProgressBar如果面板调整大小:

uses 
    CommCtrl; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    // no need to set the panel's Style to psOwnerDraw! 
    ... 
    //place the progress bar into the status bar 
    ProgressBar1.Parent := StatusBar1; 
    StatusBar1Resize(nil); 
    ... 
end; 

procedure TForm1.StatusBar1Resize(Sender: TObject); 
var 
    R: TRect; 
begin 
    //place the progress bar over the 2nd panel 
    SendMessage(StatusBar1.Handle, SB_GETRECT, 1, LPARAM(@R)); 
    ProgressBar1.SetBounds(R.Left, R.Top, R.Width, R.Height); 
end; 
+0

我完全同意ThoughtCo的代码是一个坏主意,我很尴尬,我没有正确地看过它而使用它。谢谢 – stevenvh

1

如果删除带边框的护理行它的工作原理:

// remove these lines 
ProgressBarStyle := GetWindowLong(ProgressBar1.Handle, GWL_EXSTYLE); 
ProgressBarStyle := ProgressBarStyle - WS_EX_STATICEDGE; 
SetWindowLong(ProgressBar1.Handle, GWL_EXSTYLE, ProgressBarStyle); 

产生的双边框看起来并不好看,因此在OnDrawPanel调用FillRect大卫的解决方案可能是更好的解决方案。这有额外的好处,你最终可以摆脱那个丑陋的绿色:-)。

procedure TForm1.StatusBar1DrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; 
    const Rect: TRect); 
var 
    R: TRect; 
begin 
    if Panel = StatusBar.Panels[1] then 
    begin 
    StatusBar.Canvas.Brush.Color := clBtnFace; 
    StatusBar.Canvas.FillRect(Rect); 
    R := Rect; 
    R.Right := Round(R.Left + (R.Right - R.Left) * FProgress {0..1}); 
    StatusBar.Canvas.Brush.Color := clGrayText; 
    StatusBar.Canvas.FillRect(R); 
    end; 
end; 

注意:你必须使ONDrawPanel事件处理程序被执行调用状态栏的Invalidate方法。

+0

@downvoter - 如果你不首先告诉我它有什么问题,你会如何期待我改进这个答案? – stevenvh

+1

它并没有真正回答被问及的问题。其中只有一个答案实际上是这样做的。 –

3

唯一显而易见的解释我对行为的变化是,这个代码是错误的:

ProgressBarStyle := ProgressBarStyle - WS_EX_STATICEDGE; 

此代码假定WS_EX_STATICEDGE已经在样式。但是,如果不是,那么你正在破坏窗户风格。该代码需要使用位操作:

ProgressBarStyle := ProgressBarStyle and not WS_EX_STATICEDGE; 

还要注意的是,如果重新创建窗口此窗口样式将会丢失,一些并不在VCL下发生的。更好的选择是对进度条类进行子类化并直接在覆盖的CreateParams中设置样式。

+0

奇怪的是我错过了,但它似乎是答案。也就是说,如果你喜欢绿色...... :-) – stevenvh