2017-08-03 56 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