将Delphi TLabel的字体改为斜体将尾部切掉-为什么?

将Delphi TLabel的字体改为斜体将尾部切掉-为什么?,delphi,fonts,autosize,italic,tlabel,Delphi,Fonts,Autosize,Italic,Tlabel,下面是字体设置为Arial Regular 16的默认TLabel的简单演示。 单击按钮时的代码为: procedure TForm1.Button1Click(Sender: TObject); begin Label1.Font.Style := Label1.Font.Style + [fsItalic]; end; 单击按钮时,最后一个字符被截断,即: 默认情况下,TLAbel.AutoSize为true,所以这应该可以,对吗?这在XE和Delphi7中是相同的。这是虫子吗 是

下面是字体设置为Arial Regular 16的默认TLabel的简单演示。

单击按钮时的代码为:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Label1.Font.Style := Label1.Font.Style + [fsItalic];
end;
单击按钮时,最后一个字符被截断,即:

默认情况下,TLAbel.AutoSize为true,所以这应该可以,对吗?这在XE和Delphi7中是相同的。这是虫子吗

是的,看起来是这样(虽然是一个相当小的bug)。可能的解决办法包括

  • 使用Windows API函数(或)自己绘制文本,然后
  • 使用(而不是
    TLabel
    ),它只是窗口的包装器(在文本模式下)。当然,Windows可以正确地绘制文本
使用
TextOut

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

使用静态控件(
TStaticText

我猜这在Microsoft Windows操作系统中不是问题,而只是在VCL
TLabel
控件中

更新

我试过了

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;
结果是:

因此,这毕竟是Microsoft Windows操作系统(或Arial字体)中的一个问题

解决方法是添加
DT_NOCLIP
标志:

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;

更新2

一个轻量级的补丁可能是

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;
类型
TLabel=class(StdCtrls.TLabel)
受保护的
过程DoDrawText(变量Rect:TRect;标志:整数);推翻
结束;
...
{TLabel}
过程TLabel.DoDrawText(var Rect:TRect;标志:Integer);
开始
继承;
如果(Flags和DT_calcorrect)为0,则
右矩形:=右矩形+2;
结束;
产生结果


(但是硬编码一个神奇的值(2)似乎很讨厌……

在末尾加上一个额外的空格可以很快解决这个问题。

我不相信这是一个Delphi错误,因为它只影响Arial。至少它不会影响Tahoma或Segoe用户界面,这是更常用的用户界面字体。我猜是Windows或字体本身出了问题。@Brian:请注意,在运行时不需要添加
fsItalic
,就可以显示此问题。您可以在IDE中将
FontStyle
设置为
[fsItalic]
。@andreas:我知道,谢谢。这是为了实现我使用的一个主题化例程。当AutoSize为true时,Delphi要求操作系统扩展文本,这看起来确实像Windows中的一个bug。结果似乎是错的。@Uwe:信不信由你,我认为你是对的。请看下面我的实验。TStaticText是最好的解决方法。不仅仅是因为它还可以解决调整复杂表单大小时出现的闪烁问题。这有点像是有文档记录的:“请注意,具有显著突出部分的文本可能会被剪裁,例如,文本字符串中的首字母“W”或斜体文本”。From@David:
TStaticText
的缺点是,与
TLabel
不同,它使用Windows句柄。通常情况下,在32/64位Windows下这不是问题,但当内存/资源可能很紧张时,需要记住这一点。@Ken:是的,但从新千年开始,这就不是问题了。@TLabel的缺点是在调整大小时会出现可怕的闪烁。我已经在自动调整大小的网格单元+1中使用了该修复程序,并接受了该程序,因为它适用于所有现有代码。TStaticText是个不错的主意,但在TRzPanel上不显示透明:-(