?
Solved

Auto size the panels of the statusbar

Posted on 2006-07-19
12
Medium Priority
?
716 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
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 2000 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

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

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

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
NetCrunch network monitor is a highly extensive platform for network monitoring and alert generation. In this video you'll see a live demo of NetCrunch with most notable features explained in a walk-through manner. You'll also get to know the philos…
Michael from AdRem Software outlines event notifications and Automatic Corrective Actions in network monitoring. Automatic Corrective Actions are scripts, which can automatically run upon discovery of a certain undesirable condition in your network.…
Suggested Courses
Course of the Month14 days, 14 hours left to enroll

771 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