3

我有一个TLabel设置EllipsisPositionepEndEllipsis,我需要能够判断文本当前是否被剪辑。除了自己计算显示文本所需的区域并将其与标签的实际尺寸进行比较之外,有没有人想出一种更简单/更优雅的方法来做到这一点?

实际上,以故障安全方式计算所需区域似乎也并不像听起来那么简单……例如TCanvas.GetTextHeight,不考虑换行符。

TCustomLabel.DoDrawText在内部使用DrawTextWDrawThemeTextExDT_CALCRECT标志一起确定它是否应该使用省略号。那里涉及到相当多的代码,所有这些都是声明的private。简单地复制所有这些代码在我的书中并不完全符合“优雅”的条件......

有任何想法吗?

(我正在使用 Delphi 2010,以防有人提出特定于 Delphi 版本的解决方案)

更新 1:我现在发现我可以简单地TCustomLabel.DoDrawText(lRect, DT_CALCRECT)直接调用(仅声明protected)让标签执行所需的大小计算,而无需复制其代码。我只需要确保临时设置EllipsisPositionepNone或完全使用临时标签实例。这实际上并没有那么糟糕,如果没有人能想到更简单的解决方案,我可能会接受它。

更新 2:我现在已将我的解决方案添加为单独的答案。事实证明它比我预期的更直接,所以可能没有更简单/更好的方法来做到这一点,但无论如何我都会把这个问题留一段时间,以防万一。

4

2 回答 2

3

FWIW,这就是我想出的(这是一种自定义TLabel后代的方法):

function TMyLabel.IsTextClipped: Boolean;
const
  EllipsisStr = '...';
var
  lEllipBup: TEllipsisPosition;
  lRect: TRect;
begin
  lRect := ClientRect;
  Dec(lRect.Right, Canvas.TextWidth(EllipsisStr));

  lEllipBup := EllipsisPosition;
  EllipsisPosition := epNone;
  try
    DoDrawText(lRect, DT_CALCRECT or IfThen(WordWrap, DT_WORDBREAK));
  finally
    EllipsisPosition := lEllipBup;
  end;
  Result := ((lRect.Right - lRect.Left) > ClientWidth)
         or ((lRect.Bottom - lRect.Top) > ClientHeight);
end;

由于这现在使用与(尤其是人工填充和正确的 WordWrap 设置)完全相同的逻辑,TCustomLabel.DoDrawText它还可以正确处理多行和自动换行的输入文本。请注意,在这种情况下,“正确”意味着“它总是在使用剪辑标题绘制True时返回,否则返回”。TLabelFalse

虽然上面的代码做了我最初要求的事情,但我可能不会以这种方式使用它——但这更多是由于TLabel它本身的缺点:特别是对于多行文本,它的行为通常不像我想要的那样,例如当多行没有足够的空间时,第一行的最后一个单词将始终被截断,即使整行加上省略号已经合适。

于 2010-11-30T14:46:52.563 回答
2

作为起点,您可以使用

function DrawStringEllipsis(const DC: HDC; const ARect: TRect; const AStr: string): boolean;
var
  r: TRect;
  s: PChar;
begin
  r := ARect;
  GetMem(s, length(AStr)*sizeof(char) + 8);
  StrCopy(s, PChar(AStr));
  DrawText(DC, PChar(s), length(AStr), r, DT_LEFT or DT_END_ELLIPSIS or DT_MODIFYSTRING);
  result := not SameStr(AStr, s);
  FreeMem(s);
end;

示例用法:

procedure TForm1.FormClick(Sender: TObject);
begin
  Caption := 'Clipped ' + BoolToStr(DrawStringEllipsis(Canvas.Handle, Rect(10, 100, 50, 50), 'This is a text.'), true);
end;

使用这种技术编写具有属性的TExtLabel组件并不难。WasClipped实际上,该TLabel组件是 VCL 中最简单的组件之一——它只是绘制一个字符串。

于 2010-11-30T12:35:30.440 回答