Link to home
Start Free TrialLog in
Avatar of Peter Kiers
Peter KiersFlag for Netherlands

asked on

Auto size the panels of the statusbar

Hello everybody,

Is it possible to auto size the statusbar panels?

So that the width of the panel sadjust to the text in the panel.

This is what i made when the user resizes the form
now i need help with the auto size the panels.

procedure TMainForm.StatusBar2Resize(Sender: TObject);
begin
    with StatusBar2 do
    Panels[0].Width := Width - Panels[1].Width -
    Panels[2].Width - Panels[3].Width - Panels[4].Width -
    Panels[5].Width - Panels[6].Width
end;
(*-----------------------------------------------*)
procedure TMainForm.StatusBar1Resize(Sender: TObject);
begin
  with StatusBar1 do
  Panels[0].Width := Width - Panels[1].Width -
  Panels[2].Width - Panels[3].Width - Panels[4].Width;
end;
(*-----------------------------------------------*)

Kind Regards,

Peter Kiers
Avatar of Peter Kiers
Peter Kiers
Flag of Netherlands image

ASKER

I have searched and found this:

procedure AutoSizeStatusbarPanel(sb: TStatusBar; idx:Integer);
var
   s : string;
   borders : array[0..2] of Integer;
begin
   // don't deal with simple panels
   if sb.SimplePanel
      // don't resize the last panel
      or (idx >= sb.Panels.Count-1) then
      Exit;

   // get the borders of the statusbar
   // border[0] = width of the horizontal border
   // border[1] = width of the vertical border
   // border[2] = width of the border between rectangles
   SendMessage(sb.Handle, SB_GETBORDERS, 0, Integer(@borders));

   s := sb.Panels[idx].Text;

   // calculate the width of the Panel
   sb.Panels[idx].Width := TrueFontWidth(sb.Font, s) +
      borders[2]*2 +2; // vertical border * 2 + 2 extra Pixels
end;

function TrueFontWidth(fnt: TFont; const text:string): Integer;
var
   dc: hdc;
   tsize : Windows.TSize;
begin
   dc := GetDC(0);
   SelectObject(DC, fnt.Handle);
   GetTextExtentPoint32(dc, PChar(text), Length(text), tsize);
   ReleaseDC(0, DC);
   Result := tsize.cx;
end;

But I have no idea what the procedure
and the function means!

P.
After running it i get:

[Error] Main.pas(3029): Undeclared identifier: 'SB_GETBORDERS'
Avatar of Russell Libby
Seems like the AutoSizeStatusbarPanel(sb: TStatusBar; idx:Integer);
procedure wants a status bar control and the index of the panel to autosize. Also, include the CommCtrl unit in your uses clause to fix the reference error

Regards,
Russell

Oke, i have this:

procedure TMainForm.AutoSizeStatusbarPanel(Statusbar1: TStatusBar;
  idx: Integer);
var
   s : string;
   borders : array[0..2] of Integer;
begin
   // don't deal with simple panels
   if Statusbar2.SimplePanel
      // don't resize the last panel
      or (idx >= Statusbar1.Panels.Count-1) then
      Exit;

   // get the borders of the statusbar
   // border[0] = width of the horizontal border
   // border[1] = width of the vertical border
   // border[2] = width of the border between rectangles
   SendMessage(Statusbar2.Handle, SB_GETBORDERS, 0, Integer(@borders));

   s := Statusbar2.Panels[idx].Text;

   // calculate the width of the Panel
   Statusbar1.Panels[idx].Width := TrueFontWidth(Statusbar2.Font, s) +
      borders[2]*2 +2; // vertical border * 2 + 2 extra Pixels
end;

Now my application execute, but the procedure doesn't work?

Peter
And I have this message:

[Hint] Main.pas(372): Private symbol 'AutoSizeStatusbarPanel' declared but never used

Um, not sure why you are mixing statusbar2 and statusbar1 in the same calls?. Perhaps this will clarify it a little bit. Example form code first, dfm follows

Russell

--
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  CommCtrl, StdCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    StatusBar1: TStatusBar;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

function   TrueFontWidth(fnt: TFont; const text:string): Integer;
procedure  AutoSizeStatusbarPanel(sb: TStatusBar; idx:Integer);

var
  Form1: TForm1;

implementation
{$R *.DFM}

procedure AutoSizeStatusbarPanel(sb: TStatusBar; idx:Integer);
var
   s : string;
   borders : array[0..2] of Integer;
begin
   // don't deal with simple panels
   if sb.SimplePanel
      // don't resize the last panel
      or (idx >= sb.Panels.Count-1) then
      Exit;

   // get the borders of the statusbar
   // border[0] = width of the horizontal border
   // border[1] = width of the vertical border
   // border[2] = width of the border between rectangles
   SendMessage(sb.Handle, SB_GETBORDERS, 0, Integer(@borders));

   s := sb.Panels[idx].Text;

   // calculate the width of the Panel
   sb.Panels[idx].Width := TrueFontWidth(sb.Font, s) +
      borders[2]*2 +2; // vertical border * 2 + 2 extra Pixels
end;

function TrueFontWidth(fnt: TFont; const text:string): Integer;
var
   dc: hdc;
   tsize : Windows.TSize;
begin
   dc := GetDC(0);
   SelectObject(DC, fnt.Handle);
   GetTextExtentPoint32(dc, PChar(text), Length(text), tsize);
   ReleaseDC(0, DC);
   Result := tsize.cx;
end;

procedure TForm1.Button1Click(Sender: TObject);
var  dwIndex:    Integer;
begin

  for dwIndex:=0 to Pred(StatusBar1.Panels.Count) do
     AutoSizeStatusbarPanel(StatusBar1, dwIndex);

end;

end.

--- dfm ---
object Form1: TForm1
  Left = 216
  Top = 120
  Width = 535
  Height = 197
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object StatusBar1: TStatusBar
    Left = 0
    Top = 144
    Width = 527
    Height = 19
    Panels = <
      item
        Text = 'Hello world this is a test'
        Width = 50
      end
      item
        Text = '100'
        Width = 50
      end
      item
        Text = 'Some other very long text'
        Width = 50
      end
      item
        Text = 'Delphi'
        Width = 50
      end>
    SimplePanel = False
  end
  object Button1: TButton
    Left = 16
    Top = 12
    Width = 75
    Height = 25
    Caption = 'Button1'
    TabOrder = 1
    OnClick = Button1Click
  end
end

Hi,

Thank you for the example, your example works fine.
But not in my application, and I think the problem is
that i dont have to autosize all the panels.

I have 7 panels (0 to 6) and I want only panel 1,3  and 5
to autosize.

Peter
???? Then use

  AutoSizeStatusbarPanel(StatusBar1, 1);
  AutoSizeStatusbarPanel(StatusBar1, 3);
  AutoSizeStatusbarPanel(StatusBar1, 5);

My code was a demo of usage only. If you want to autosize only 1 panel, then pass the owning statusbar and the panel index. If you want to do it for 3 panels, then call the function 3 times. if you need to do it for another status bar, then pass that status bar in.

  AutoSizeStatusbarPanel(StatusBar2, 1);

If you are having trouble then please post the code you have.

Russell

I try and I try, but no luck sofar...

procedure TMainForm.FormCreate(Sender: TObject);
var
  dwIndex:    Integer;
begin
  AutoSizeStatusbarPanel(StatusBar2, 1);
  AutoSizeStatusbarPanel(StatusBar2, 3);
  AutoSizeStatusbarPanel(StatusBar2, 5);
end;
(*-----------------------------------------------*)
procedure TMainForm.AutoSizeStatusbarPanel(sb: TStatusBar; idx: Integer);
var
   s : string;
   borders : array[0..2] of Integer;
begin
   // don't deal with simple panels
   if sb.SimplePanel
      // don't resize the last panel
      or (idx >= sb.Panels.Count-1) then
      Exit;

   // get the borders of the statusbar
   // border[0] = width of the horizontal border
   // border[1] = width of the vertical border
   // border[2] = width of the border between rectangles
   SendMessage(sb.Handle, SB_GETBORDERS, 0, Integer(@borders));

   s := sb.Panels[idx].Text;

   // calculate the width of the Panel
   sb.Panels[idx].Width := TrueFontWidth(sb.Font, s) +
      borders[2]*2 +2; // vertical border * 2 + 2 extra Pixels
end;
(*-----------------------------------------------*)
function TMainForm.TrueFontWidth(fnt: TFont; const text: string): Integer;
var
   dc: hdc;
   tsize : Windows.TSize;
begin
   dc := GetDC(0);
   SelectObject(DC, fnt.Handle);
   GetTextExtentPoint32(dc, PChar(text), Length(text), tsize);
   ReleaseDC(0, DC);
   Result := tsize.cx;
end;
(*-----------------------------------------------*)
procedure TMainForm.StatusBar2Resize(Sender: TObject);
begin
  with StatusBar2 do
  Panels[0].Width := Width - Panels[1].Width -
  Panels[2].Width - Panels[3].Width - Panels[4].Width -
  Panels[5].Width - Panels[6].Width;
end;
(*-----------------------------------------------*)

Peter
ASKER CERTIFIED SOLUTION
Avatar of Russell Libby
Russell Libby
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
It works perfectly.

Thank you.

500 point comming your way...

Bye.

P.

And thank you Peter..

Russell