将TProgressBar放置在TStatusBar上的方法不再有效

时间:2017-08-03 07:44:09

标签: delphi delphi-xe8

过去我使用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。

这是否意味着此方法不合适?这样做的正确方法是什么?

3 个答案:

答案 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事件处理程序。