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

Author: Scott Hollows

Enterprise software developer based in Perth, Western Australia. Focused on Oracle, Delphi, Data Warehouse design and ETL, Data Architect, Business Intelligence, Oracle performance tuning. President of the Australian Delphi User Group (ADUG) LinkedIn www.linkedin.com/in/scotthollows

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s