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?

Brian Frost
  • 13,334
  • 11
  • 80
  • 154
  • 2
    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. – David Heffernan May 26 '11 at 16:05
  • @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. – Andreas Rejbrand May 26 '11 at 16:09
  • @andreas: I know, thanks. This is to implement a theming routine that I use. – Brian Frost May 26 '11 at 16:39
  • 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. – Uwe Raabe May 26 '11 at 16:45
  • @Uwe: Believe it or not, I think you are right. See my experiment below. – Andreas Rejbrand May 26 '11 at 17:01
  • 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). – Jeroen Wiert Pluimers May 26 '11 at 17:33
  • that sounds plausible. Explains what I found that it is very font specific. – David Heffernan May 26 '11 at 17:38

2 Answers2

10

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

Tim
  • 1,549
  • 1
  • 20
  • 37
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...)

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • 1
    TStaticText is the best workaround for this. Not least because it will also workaround flicker problems when resizing complex forms. – David Heffernan May 26 '11 at 16:05
  • 3
    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](http://msdn.microsoft.com/en-us/library/dd162498%28v=vs.85%29.aspx). – Sertac Akyuz May 26 '11 at 17:23
  • @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. – Ken White May 26 '11 at 21:35
  • 1
    @Ken: Yes, but this hasn't been a problem since the turn of the millenium. – Andreas Rejbrand May 26 '11 at 21:38
  • @the drawback to TLabel is the diabolical flicker on resizing – David Heffernan May 26 '11 at 21:40
  • @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**). – Ken White May 28 '11 at 15:11