In the past I used the method described here to place a TProgressBar on a TStatusBar in Delphi:
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;
But (after a recent Windows update?) this no longer works, i.e. the old programs still work as expected, but newly compiled ones don't. I'm using the same Delphi version, XE8, on Windows 10.
Does this mean that this method was inappropriate? What is the right way to do this?
As others have explained, your mismanagement of the TProgressBar
's window styles is the cause of your problem.
I want to add that you do not need to use (and should not be using) the TStatusBar.OnDrawPanel
event to position the TProgressBar
at all. It is a drawing event, not an object management event. If you are not going to manually draw a progress bar onto the TStatusBar.Canvas
then you should get rid of the OnDrawPanel
handler completely.
You can instead position the TProgressBar
one time at startup, by using the SB_GETRECT
message to get the panel's coordinates and dimensions and then position the TProgressBar
accordingly, eg:
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;
If your Form is resizable, you can use the TStatusBar.OnResize
event to reposition the TProgressBar
if the panel resizes:
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;