stacker_liew 5 Posted May 12, 2022 Like this Link I tried in Windows 10, using D10.4, it has no effect. Share this post Link to post
PeterBelow 239 Posted May 12, 2022 2 hours ago, stacker_liew said: Like this Link I tried in Windows 10, using D10.4, it has no effect. If you used the button OnClick handler from the link you gave it will not work unless uncomment the Application.ProcessMesssages call. Share this post Link to post
stacker_liew 5 Posted May 12, 2022 41 minutes ago, PeterBelow said: If you used the button OnClick handler from the link you gave it will not work unless uncomment the Application.ProcessMesssages call. I tried with Application.ProcessMessage still no effect for ProgressBar. Share this post Link to post
Remy Lebeau 1436 Posted May 12, 2022 (edited) 42 minutes ago, PeterBelow said: it will not work unless uncomment the Application.ProcessMesssages call Or, at the very least, calling Update() on the TProgressBar or TForm. Or, the example shown, by simply using a timer or thread instead of a blocking loop, let the main message queue run unblocked and handle UI updates normally. That being said, TStatusBar is not really intended to host child controls. And using a *drawing* event to update UI layout is a big no-no in general. Any time I've ever needed to show a progress bar inside of a status bar (or, any other non-container parent, such as TListView or TTreeView, etc), I always prefer to owner-draw the parent and actually draw a progress bar myself. I never try to hack in a TProgressBar as a child control. Especially in a parent that can be resized/scrolled at runtime. Keeping a TProgressBar positioned correctly at all times can get ugly quick. Edited May 12, 2022 by Remy Lebeau Share this post Link to post
stacker_liew 5 Posted May 12, 2022 1 hour ago, Remy Lebeau said: Or, at the very least, calling Update() on the TProgressBar or TForm. Or, the example shown, by simply using a timer or thread instead of a blocking loop, let the main message queue run unblocked and handle UI updates normally. That being said, TStatusBar is not really intended to host child controls. And using a *drawing* event to update UI layout is a big no-no in general. Any time I've ever needed to show a progress bar inside of a status bar (or, any other non-container parent, such as TListView or TTreeView, etc), I always prefer to owner-draw the parent and actually draw a progress bar myself. I never try to hack in a TProgressBar as a child control. Especially in a parent that can be resized/scrolled at runtime. Keeping a TProgressBar positioned correctly at all times can get ugly quick. Any example of these? Share this post Link to post
David Heffernan 2353 Posted May 12, 2022 I also owner draw into a status bar panel for this need. It's pretty straightforward. Share this post Link to post
aehimself 399 Posted May 12, 2022 I create my progress bars in the first panel of the status bar, with a label on it to show some meaningful information on the progress... like "30 of 999 items processed". Yes, it won't work if you resize the panel, needs some adjustments if you want to create it in the 3rd, but this is the code I use: Unit uProgressBarInStatusBar; Interface Uses Vcl.ComCtrls, Vcl.StdCtrls; Type TProgressBarInStatusBar = Class public Class Procedure CreateIn(Const inStatusBarPanel: TStatusPanel; Var outProgressBar: TProgressBar; Var outLabel: TLabel); End; Implementation Uses Vcl.Controls, System.Classes; Class Procedure TProgressBarInStatusBar.CreateIn(Const inStatusBarPanel: TStatusPanel; Var outProgressBar: TProgressBar; Var outLabel: TLabel); Var statusbar: TStatusBar; Begin statusbar := inStatusBarPanel.Collection.Owner As TStatusBar; outProgressBar := TProgressBar.Create(statusbar); outProgressBar.Parent := statusbar; outProgressBar.Top := 2; outProgressBar.Left := 1; outProgressBar.Width := inStatusBarPanel.Width - 3; outProgressBar.Height := statusbar.ClientHeight - 3; outLabel := TLabel.Create(outProgressBar); outLabel.Parent := outProgressBar; outLabel.Align := alClient; outLabel.AutoSize := False; outLabel.Alignment := taCenter; End; End. The small sacrifice of having it in the first panel makes up to it with no custom drawings / hacks needed at all. And it looks good enough: Share this post Link to post
stacker_liew 5 Posted May 12, 2022 3 hours ago, aehimself said: I create my progress bars in the first panel of the status bar, with a label on it to show some meaningful information on the progress... like "30 of 999 items processed". Yes, it won't work if you resize the panel, needs some adjustments if you want to create it in the 3rd, but this is the code I use: Unit uProgressBarInStatusBar; Interface Uses Vcl.ComCtrls, Vcl.StdCtrls; Type TProgressBarInStatusBar = Class public Class Procedure CreateIn(Const inStatusBarPanel: TStatusPanel; Var outProgressBar: TProgressBar; Var outLabel: TLabel); End; Implementation Uses Vcl.Controls, System.Classes; Class Procedure TProgressBarInStatusBar.CreateIn(Const inStatusBarPanel: TStatusPanel; Var outProgressBar: TProgressBar; Var outLabel: TLabel); Var statusbar: TStatusBar; Begin statusbar := inStatusBarPanel.Collection.Owner As TStatusBar; outProgressBar := TProgressBar.Create(statusbar); outProgressBar.Parent := statusbar; outProgressBar.Top := 2; outProgressBar.Left := 1; outProgressBar.Width := inStatusBarPanel.Width - 3; outProgressBar.Height := statusbar.ClientHeight - 3; outLabel := TLabel.Create(outProgressBar); outLabel.Parent := outProgressBar; outLabel.Align := alClient; outLabel.AutoSize := False; outLabel.Alignment := taCenter; End; End. The small sacrifice of having it in the first panel makes up to it with no custom drawings / hacks needed at all. And it looks good enough: Thanks, how to use it? Share this post Link to post
aehimself 399 Posted May 13, 2022 Something like this: Var pbar: TProgressBar; lbl: TLabel; a: Integer; Begin TProgressBarInStatusBar.CreateIn(StatusBar1, pbar, lbl); For a := 0 To 1000 Do Begin pbar.Position := a Div 10; lbl.Caption := 'Working ' + a.ToString + '...'; Application.ProcessMessages; // Don't do this. It's just pseudocode. Sleep(500); End; End; Share this post Link to post
stacker_liew 5 Posted May 13, 2022 8 hours ago, aehimself said: Something like this: Var pbar: TProgressBar; lbl: TLabel; a: Integer; Begin TProgressBarInStatusBar.CreateIn(StatusBar1, pbar, lbl); For a := 0 To 1000 Do Begin pbar.Position := a Div 10; lbl.Caption := 'Working ' + a.ToString + '...'; Application.ProcessMessages; // Don't do this. It's just pseudocode. Sleep(500); End; End; Thanks Share this post Link to post
stacker_liew 5 Posted May 15, 2022 On 5/13/2022 at 4:04 PM, aehimself said: Something like this: Var pbar: TProgressBar; lbl: TLabel; a: Integer; Begin TProgressBarInStatusBar.CreateIn(StatusBar1, pbar, lbl); For a := 0 To 1000 Do Begin pbar.Position := a Div 10; lbl.Caption := 'Working ' + a.ToString + '...'; Application.ProcessMessages; // Don't do this. It's just pseudocode. Sleep(500); End; End; Does this method support multiple TStatusPanel? I tried with a TStatusPanel in Panel[1], but the ProgressBar, still appear in Panel[0]. Share this post Link to post
Remy Lebeau 1436 Posted May 15, 2022 (edited) 32 minutes ago, stacker_liew said: Does this method support multiple TStatusPanel? I tried with a TStatusPanel in Panel[1], but the ProgressBar, still appear in Panel[0]. That is because the TProgressBarInStatusBar.CreateIn() code provided earlier is not taking the Left position of the specified TStatusPanel into account, only its Width and Height. So it is positioning the TProgressBar in the wrong place for any TStatusPanel other than the 1st one. Unfortunately, neither TStatusBar nor TStatusPanel provide a property or method to get the Left position of a TStatusPanel, so you will have to retrieve it manually, either by: - looping through the TStatusBar.Panels collection: function GetLeftOfStatusPanel(APanel: TStatusPanel); Integer; var I: Integer; Coll: TStatusPanels; begin Result := 0; Coll := APanel.Collection as TStatusPanels; for I := 0 to APanel.Index-1 do Inc(Result, Coll[I].Width); end; - or by asking the OS directly: uses ..., Winapi.CommCtrl; function GetLeftOfStatusPanel(APanel: TStatusPanel); Integer; var R: TRect; begin SendMessage((APanel.Collection.Owner as TStatusBar).Handle, SB_GETRECT, APanel.Index, LPARAM(@R)); Result := R.Left; end; In which case, since CreateIn() wants the TProgressBar to fill the full rectangle of the TStatusPanel anyway, I would just ask the OS for the rectangle and use it as-is, eg: uses ..., Winapi.CommCtrl; class procedure TProgressBarInStatusBar.CreateIn(const inStatusBarPanel: TStatusPanel; var outProgressBar: TProgressBar; var outLabel: TLabel); var statusbar: TStatusBar; R: TRect; Begin statusbar := inStatusBarPanel.Collection.Owner As TStatusBar; SendMessage(statusbar.Handle, SB_GETRECT, inStatusBarPanel.Index, LPARAM(@R)); outProgressBar := TProgressBar.Create(statusbar); outProgressBar.Parent := statusbar; outProgressBar.Top := R.top; outProgressBar.Left := R.left; outProgressBar.Width := R.Width; outProgressBar.Height := R.Height; outLabel := TLabel.Create(outProgressBar); outLabel.Parent := outProgressBar; outLabel.Align := alClient; outLabel.AutoSize := False; outLabel.Alignment := taCenter; end; Edited May 15, 2022 by Remy Lebeau 1 Share this post Link to post
stacker_liew 5 Posted May 15, 2022 45 minutes ago, Remy Lebeau said: That is because the TProgressBarInStatusBar.CreateIn() code provided earlier is not taking the Left position of the specified TStatusPanel into account, only its Width and Height. So it is positioning the TProgressBar in the wrong place for any TStatusPanel other than the 1st one. Unfortunately, neither TStatusBar nor TStatusPanel provide a property or method to get the Left position of a TStatusPanel, so you will have to retrieve it manually, either by: - looping through the TStatusBar.Panels collection: function GetLeftOfStatusPanel(APanel: TStatusPanel); Integer; var I: Integer; Coll: TStatusPanels; begin Result := 0; Coll := APanel.Collection as TStatusPanels; for I := 0 to APanel.Index-1 do Inc(Result, Coll[I].Width); end; - or by asking the OS directly: uses ..., Winapi.CommCtrl; function GetLeftOfStatusPanel(APanel: TStatusPanel); Integer; var R: TRect; begin SendMessage((APanel.Collection.Owner as TStatusBar).Handle, SB_GETRECT, APanel.Index, LPARAM(@R)); Result := R.Left; end; In which case, since CreateIn() wants the TProgressBar to fill the full rectangle of the TStatusPanel anyway, I would just ask the OS for the rectangle and use it as-is, eg: uses ..., Winapi.CommCtrl; class procedure TProgressBarInStatusBar.CreateIn(const inStatusBarPanel: TStatusPanel; var outProgressBar: TProgressBar; var outLabel: TLabel); var statusbar: TStatusBar; R: TRect; Begin statusbar := inStatusBarPanel.Collection.Owner As TStatusBar; SendMessage(statusbar.Handle, SB_GETRECT, inStatusBarPanel.Index, LPARAM(@R)); outProgressBar := TProgressBar.Create(statusbar); outProgressBar.Parent := statusbar; outProgressBar.Top := R.top; outProgressBar.Left := R.left; outProgressBar.Width := R.Width; outProgressBar.Height := R.Height; outLabel := TLabel.Create(outProgressBar); outLabel.Parent := outProgressBar; outLabel.Align := alClient; outLabel.AutoSize := False; outLabel.Alignment := taCenter; end; Thanks, it works now. Share this post Link to post
stacker_liew 5 Posted May 15, 2022 18 minutes ago, stacker_liew said: Thanks, it works now. BTW, how to handle when the form is resized while the processing is doing? Share this post Link to post
aehimself 399 Posted May 15, 2022 9 hours ago, stacker_liew said: BTW, how to handle when the form is resized while the processing is doing? You either manually set the position on the form's OnResize event or set the proper anchors after creating the components. Share this post Link to post
stacker_liew 5 Posted May 16, 2022 On 5/15/2022 at 7:45 PM, aehimself said: You either manually set the position on the form's OnResize event or set the proper anchors after creating the components. Setting the acnchors after creating the components doesn't work. Share this post Link to post
stacker_liew 5 Posted May 16, 2022 20 minutes ago, stacker_liew said: Setting the acnchors after creating the components doesn't work. Done with setting the correct position and size on the form's OnResize event, thanks. Share this post Link to post