Solved

Auto size the panels of the statusbar

Posted on 2006-07-19
12
686 Views
Last Modified: 2010-04-05
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
0
Comment
Question by:peterkiers
  • 7
  • 5
12 Comments
 
LVL 1

Author Comment

by:peterkiers
ID: 17138484
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.
0
 
LVL 1

Author Comment

by:peterkiers
ID: 17138746
After running it i get:

[Error] Main.pas(3029): Undeclared identifier: 'SB_GETBORDERS'
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 17138974
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

0
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 1

Author Comment

by:peterkiers
ID: 17139074
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
0
 
LVL 1

Author Comment

by:peterkiers
ID: 17139124
And I have this message:

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

Expert Comment

by:Russell Libby
ID: 17139143

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

0
 
LVL 1

Author Comment

by:peterkiers
ID: 17139460
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
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 17139528
???? 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

0
 
LVL 1

Author Comment

by:peterkiers
ID: 17139620
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
0
 
LVL 26

Accepted Solution

by:
Russell Libby earned 500 total points
ID: 17139731
Get rid of the handling in the form create, and change your StatusBar2Resize logic to this:

procedure TMainForm.StatusBar2Resize(Sender: TObject);
begin

  AutoSizeStatusbarPanel(StatusBar2, 1);
  AutoSizeStatusbarPanel(StatusBar2, 3);
  AutoSizeStatusbarPanel(StatusBar2, 5);
  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;

The above worked fine for me, as it kept panels 1 3 and 5 to the proper size. Now, if you are setting a panel's text somewhere in code, you need to remebemer to Autosize the panel after the text has been set, eg:

 StatusBar2.Panels[1].Text:='Some new text';
 AutoSizeStatusbarPanel(StatusBar2, 1);

---

Russell



0
 
LVL 1

Author Comment

by:peterkiers
ID: 17140158
It works perfectly.

Thank you.

500 point comming your way...

Bye.

P.
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 17140191

And thank you Peter..

Russell
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…

861 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question