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

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Multi-Line Captions for TLabel, TPanel and Buttons. Delphi VCL and FireMonkey
Scott Hollows - 29/Oct/2016
[SHOWTOGROUPS=4,20]
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. Для просмотра ссылки Войди или Зарегистрируйся 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 thisMy 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.

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

[/SHOWTOGROUPS]