Changing the font of a Delphi TLabel to Italic chops off the tail - why?
Asked Answered
C

2

9

A simple demo of a default TLabel with font set to Arial Regular 16 is shown below. enter image description here

The code when the button is clicked is:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Label1.Font.Style := Label1.Font.Style + [fsItalic];
end;

When you click the button, the last character is truncated viz:

enter image description here

By default, TLAbel.AutoSize is true so this should be ok, right? This is in XE and Delphi 7 is the same. Is this a bug?

Custard answered 26/5, 2011 at 15:46 Comment(7)
I'm not convinced that this is a Delphi bug since it only afflicts Arial. At least it doesn't afflict Tahoma or Segoe UI which are more commonly used UI fonts. My guess is that the fault lies in either Windows or the font itself.Cirrhosis
@Brian: Notice that you don't need to add fsItalic during runtime in order to display this issue. You can just set FontStyle to [fsItalic] in the IDE.Valentinevalentino
@andreas: I know, thanks. This is to implement a theming routine that I use.Custard
It looks indeed like a bug in Windows as Delphi asks the OS for the extension of the text when AutoSize is true. The result seems to be wrong.Supertax
@Uwe: Believe it or not, I think you are right. See my experiment below.Valentinevalentino
It is a font problem in Windows, where the width of the character box is not adjusted when you ask for an italic or bold variation of a font, and that specific variation is not installed in Windows (so Windows approximates bold/italic by moving around some pixels).Lactation
that sounds plausible. Explains what I found that it is very font specific.Cirrhosis
S
10

An extra space at the end is a quick work around for this.

Sylvan answered 26/5, 2011 at 15:51 Comment(2)
I've used that fix in auto sized grid cellsKandrakandy
+1 and accepted since this works with all existing code. TStaticText is a nice idea but does not show transparent over a TRzPanel :-(Custard
V
7

Yes, it would seem so (although a rather minor bug). Possible work-arounds include

  • drawing the text yourself, using the Windows API function TextOut (or DrawText), and
  • using a TStaticText (instead of a TLabel), which is merely a wrapper for a Windows static control (in text mode). Of course, Windows draws the text correctly.

Using TextOut

procedure TForm4.FormPaint(Sender: TObject);
const
  S = 'This is a test';
begin
  TextOut(Canvas.Handle,
    10,
    10,
    PChar(S),
    length(S));
end;

TextOut sample

Using a static control (TStaticText)

Static control sample

I would guess that this is not a problem in the Microsoft Windows operating system, but only in the VCL TLabel control.

Update

I tried

procedure TForm4.FormPaint(Sender: TObject);
const
  S = 'This is a test';
var
  r: TRect;
begin
  r.Left := 10;
  r.Top := 10;
  r.Bottom := r.Top + DrawText(Canvas.Handle,
    PChar(S),
    length(S),
    r,
    DT_SINGLELINE or DT_LEFT or DT_CALCRECT);
  DrawText(Canvas.Handle,
    PChar(S),
    length(S),
    r,
    DT_SINGLELINE or DT_LEFT);
end;

and the result is this:

DrawText sample

Thus, this is a problem in the Microsoft Windows operating system (or the Arial font), after all.

A workaround is to add the DT_NOCLIP flag:

procedure TForm4.FormPaint(Sender: TObject);
const
  S = 'This is a test';
var
  r: TRect;
begin
  r.Left := 10;
  r.Top := 10;
  r.Bottom := r.Top + DrawText(Canvas.Handle,
    PChar(S),
    length(S),
    r,
    DT_SINGLELINE or DT_LEFT or DT_CALCRECT);
  DrawText(Canvas.Handle,
    PChar(S),
    length(S),
    r,
    DT_SINGLELINE or DT_LEFT or DT_NOCLIP);
end;

DrawText with DT_NOCLIP sample

Update 2

A light-weight fix might be

type
  TLabel = class(StdCtrls.TLabel)
  protected
    procedure DoDrawText(var Rect: TRect; Flags: Integer); override;
  end;

...

{ TLabel }

procedure TLabel.DoDrawText(var Rect: TRect; Flags: Integer);
begin
  inherited;
  if (Flags and DT_CALCRECT) <> 0 then
    Rect.Right := Rect.Right + 2;
end;

yielding the result

TLabel with slight modification

(But hard-coding a magic value (2) seems nasty...)

Valentinevalentino answered 26/5, 2011 at 15:51 Comment(6)
TStaticText is the best workaround for this. Not least because it will also workaround flicker problems when resizing complex forms.Cirrhosis
It is kind of documented: "Note that text with significant overhang may be clipped, for example, an initial "W" in the text string or text that is in italics". From DrawText Function.Incontestable
@David: The drawback to TStaticText is that, unlike TLabel, it uses a Windows handle. Typically this isn't a problem under 32/64-bit Windows, but it's something to keep in mind when memory/resources might be tight.Somatoplasm
@Ken: Yes, but this hasn't been a problem since the turn of the millenium.Valentinevalentino
@the drawback to TLabel is the diabolical flicker on resizingCirrhosis
@Andreas: I know that - that's why I said "Typically...not a problem", and "when memory/resources might be tight". :) @David: That's what double-buffering helps prevent (note I didn't say stops).Somatoplasm

© 2022 - 2024 — McMap. All rights reserved.