Search code examples
delphicolorsc++builderstatusbarondraw

Changing the color of one TStatusPanel after initial program load in Delphi?


I've got a program with a status bar at the bottom containing three elements. I'd like to redraw the second element in a different font color to signify that a user is valid. The first part of my question is:

a) How can I redraw the text in a different color to the default text?

and b) How can I draw the text in a different color after an event is triggered (For example a button push)?

My current code is below. I'm trying to check whether the condition for the panel to be repainted in a different color is correct (CurrentUser.Valid, which is a boolean), and then trying to recolor the text. This currently does not work.

procedure TChatFormMain.sbarMainDrawPanel(StatusBar: TStatusBar;
  Panel: TStatusPanel; const Rect: TRect);
var
  RectForText: TRect;
begin
  if (Panel = StatusBar.Panels[1]) and (CurrentUser.Valid) then
  begin
    sbarMain.Canvas.Font.Color := clGreen;
    RectForText := Rect;
    StatusBar.Canvas.FillRect(RectForText);
    DrawText(sbarMain.Canvas.Handle, PChar(Panel.Text), -1, RectForText,
      DT_SINGLELINE or DT_VCENTER or DT_LEFT);
  end;
end;

In another part of the code I'm calling StatusBar.repaint; to try and redraw the bar with the new text colour, is this correct?

Update MCVE:

unit colourStatusU;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls;

type
  TForm1 = class(TForm)
    StatusBar1: TStatusBar;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure StatusBar1DrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel;
      const Rect: TRect);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  valid : boolean;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  valid := true;
  StatusBar1.Repaint;
end;

procedure TForm1.StatusBar1DrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel;
  const Rect: TRect);
var
  RectForText: TRect;
begin
  if (Panel = StatusBar.Panels[1]) and (Valid) then
  begin
    Canvas.Font.Color := clGreen;
    RectForText := Rect;
    Canvas.FillRect(RectForText);
    DrawText(Canvas.Handle, PChar(Panel.Text), -1, RectForText,
      DT_SINGLELINE or DT_VCENTER or DT_LEFT);
  end;
end;

end.

Solution

  • The OnDrawPanel event is called only for a panel that has its Style set to psOwnerDraw, so make sure you have set the Style properly, either in the Object Inspector or in code.

    The Canvas to paint on must be the TStatusBar.Canvas, but you are using the TForm.Canvas instead. Use the Canvas of the StatusBar that is provided by the OnDrawPanel event:

    procedure TForm1.StatusBar1DrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel;
      const Rect: TRect);
    var
      RectForText: TRect;
    begin
      if (Panel = StatusBar.Panels[1]) and (Valid) then
      begin
        StatusBar.Canvas.Font.Color := clGreen;
        RectForText := Rect;
        StatusBar.Canvas.FillRect(RectForText);
        DrawText(StatusBar.Canvas.Handle, PChar(Panel.Text), -1, RectForText, DT_SINGLELINE or DT_VCENTER or DT_LEFT);
      end;
    end;
    

    Calling Repaint() or Invalidate() to force the Statusbar to refesh its painting is the method to use.