Multi-Line Captions for TLabel, TPanel and Buttons. Delphi VCL and FireMonkey

Implement multi-line captions in Delphi for TPanel, Tlabel and buttons (TButton, TSpeedButton, TBitBtn)

This is native Delphi code.  You don’t need to hack the form’s text file

VCL and FireMonkey source code is included

multi_line_controls

This is a follow on from my recent post about Multi-Line Popup Hints.  That got me thinking about multi-line captions so Ive provided a solution for that here.

Supports

  • Delphi 10.1 Berlin – it should also work on many earlier versions
  • VCL and FireMonkey – separate units for each
  • Various Controls TButton, TSpeedButton, TBitBtn, TLabel, TPanel and descendents.
    Contact me if you need any others supported
  • Any location – the controls can be on a form, panel or frame

Instructions

  1. Download the source files
  2. Add the VCL or FireMonkey unit to your project or search path
  3. Add the unit to USES
    – For VCL projects … uses MultiLineControlVCLu
    – For FireMonkey projects … uses MultiLineControlFMXu
  4. Add a tilde character “~” to the caption of your button / panel / label where you want the text to split, like this
    My Button Caption Line 1~My Button Caption Line 2
    
  5. Add this code to your form’s OnCreate event
begin
          // setup multi-line captions for the form
          // and all child objects
  SetupMultiLineCaptionAll (
         self // this can be a form,frame,button,label,panel
         );
end;

5. Run the project.  The “~” character will be used to split the lines like this

My Button Caption Line 1
My Button Caption Line 2

Go ahead.   You can do it !
Supportive Manatee believes in you
multi_line_controls_manatee

Behind The Scenes

That’s all that you need to know to get multi-line captions up and running.

The rest of this post will cover behind the scenes details that is not essential reading.

If you are not going to read further, please +1 vote for me on Delphi Feeds and BeginEnd

Technique Overview

The new line is achieved by using a tag character “~” in the captain text.  This is replaced at runtime with an ASCII #10 new line character, similar to this

MyButton.Caption := AnsiReplaceStr (MyButton.Caption,'~', #10);

That means this caption …

My Button Caption Line 1~My Button Caption Line 2

will get converted to …

My Button Caption Line 1
My Button Caption Line 2

VCL TPanel and VCL Button need some extra tweaking, so lets look at those now.

VCL TButton needs Windows Magic

The #10 trick does not work with TButton

However, we can make it work with use this Windows Magic …

uses WinApi.Windows;
{snip}
        // make button caption multi-line
SetWindowLong( 
          MyButton.Handle
         ,GWL_STYLE
         ,GetWindowLong (
             (aControl as TWinControl).Handle, GWL_STYLE)
             or BS_MULTILINE
             );

This is only needed for VCL.
The FireMonkey TButton doesn’t need this as it supports multi-line #10 out of the box

Tweaking for VCL TPanel

VCL TPanel is stubborn enough to resist #10 and magic.

So instead, my code uses brute force to get a multi-line caption in TPanel.

  • Remove the panel caption text
  • Create a multi-line TLabel at runtime
  • Adjustments to make the label have the same appearance as the panel caption
    – same position
    – same text
    – send to back

Bonus – multi-line popup hints

I merged the multi-line popup hints that I covered here into the same unit.

Doesn’t FMX TLabel already supports multi-line ?

FireMonkey TLabel supports word wrapping by default, so if you increase the height of the TLabel it will wrap its text over multiple lines.  However, the wrapping is out of your control and it wraps wherever it wants to.  The technique on this page will allow you to control where the new line break occurs.

Hard Coded Types or Dynamic RTTI

I originally hard coded for each type of control that I wanted to support like this

if   aComponent is TSpeedButton then
     {blah}

After a while, I decided to rewrite it with RTTI calls, which meant it would work with any type control that had a caption property without the need to include the control’s unit

This also reduced the compiled size as superfluous units did not need to be compiled into the executable

The original code is still in the unit, but commented out.

API

  • Setup a single control (Button, Label, Panel)
procedure SetupMultiLineCaption (aComponent : TComponent);
procedure SetupMultiLineHint    (aComponent : TComponent);
  • Setup all controls on a form
procedure SetupMultiLine (
    aComponent : TComponent; // form,frame,button,label or panel
    aMultiLineHint    : boolean;
    aMultiLineCaption : boolean
    );
  • Setup a panel for multi-line caption
function SetPanelCaptionMultiLine (
    aPanel   : TPanel;
    aCaption : string
    ) : TLabel;
  // creates and returns a TLabel that acts as the panel caption

Download

Download VCL and FireMonkey source code and demo

+1 this post

If you like this post, please +1 vote here to get this listed on Delphi Feeds

and also here on BeginEnd

Thank You !

About The Author

scott_circle
The Usual Suspect
– Scott Hollows –

  • Oracle and Delphi software developer.
  • Australian Delphi User Group – Western Australia Chief Cat Herder
  • Australian Delphi User Group – President
blog email linkedinlogo

Published by

3 responses to “Multi-Line Captions for TLabel, TPanel and Buttons. Delphi VCL and FireMonkey”

  1. Not working in 10.4

  2. Hi Duhaczek

    I tested this today in Delphi 10.4 and it worked correctly as described above.
    You see a single line in the IDE, but multiple lines at runtime after you call the procedure.

    procedure SetupMultiLine (
    self // aComponent : TComponent form,frame,button,label or panel
    ,TRUE // aMultiLineHint : boolean
    ,TRUE // aMultiLineCaption : boolean
    );

    Please try again. If it does not work, please send me some screen shots and the code that you are using to set it up.

  3. UPDATE – Delphi 12 has just been released (Nov-2023)

    It now allows multiple lines for the Hint property of all controls and the Caption property of some controls (why not all controls ???)

Leave a comment