过去我使用here描述的方法在Delphi中的TStatusBar上放置TProgressBar:
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更新之后?)这不再有效,即旧程序仍然按预期工作,但新编译的程序不能。我在Windows 10上使用相同的Delphi版本XE8。
这是否意味着此方法不合适?这样做的正确方法是什么?
答案 0 :(得分:4)
我对行为改变的唯一明显解释是这段代码错了:
ProgressBarStyle := ProgressBarStyle - WS_EX_STATICEDGE;
此代码假定WS_EX_STATICEDGE
已经在样式中。但如果不是那么你正在摧毁窗户风格。该代码需要使用按位运算:
ProgressBarStyle := ProgressBarStyle and not WS_EX_STATICEDGE;
另请注意,如果重新创建窗口,此窗口样式将丢失,这在VCL下会发生。更好的选择是子类化进度条类并直接在重写的CreateParams
中设置样式。
答案 1 :(得分:4)
正如其他人所解释的那样,TProgressBar
窗口样式的错误管理是导致问题的原因。
我想补充一点,您不需要使用(并且不应该使用)TStatusBar.OnDrawPanel
事件来定位TProgressBar
。它是一个绘图事件,而不是对象管理事件。如果您不打算在TStatusBar.Canvas
上手动绘制进度条,那么您应该完全摆脱OnDrawPanel
处理程序。
您可以使用SB_GETRECT
消息获取面板的坐标和尺寸,然后相应地定位TProgressBar
,例如:
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
答案 2 :(得分:1)
如果你删除了处理边框的线条,它会起作用:
// remove these lines
ProgressBarStyle := GetWindowLong(ProgressBar1.Handle, GWL_EXSTYLE);
ProgressBarStyle := ProgressBarStyle - WS_EX_STATICEDGE;
SetWindowLong(ProgressBar1.Handle, GWL_EXSTYLE, ProgressBarStyle);
生成的双边框看起来不太好,因此David在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;
注意:您必须调用StatusBar的Invalidate
方法,以便执行ONDrawPanel事件处理程序。