Delphi - 在矩形框中央绘制多行文本

9
在Delphi中,我想在TRect内部绘制文本。我希望具有以下功能:
  1. 将文本垂直居中绘制在TRect内
  2. 将文本水平居中绘制在TRect内
  3. 如果可以容纳多行文本(使用TRect的高度),则绘制多行文本
  4. 如果文本无法适应TRect(单行或多行),则将省略号添加到文本中。
我可以看到Windows.DrawText()函数几乎覆盖了这个功能,但是在编写文本时,多行和垂直居中是互斥的。
我想知道这个功能是否内置在Windows(2000+)中?如果没有,是否有一种方法可以在不编写自己的函数的情况下完成此操作?

2
你不能使用TLabel吗?我认为它具备所需的所有功能。 - Andriy M
1
是的,它可能会,但我不想使用标签,我有一个画布可以绘制。 - Simon
2个回答

23

抱歉,这是之前所有答案和评论的结合体。但似乎楼主需要更多帮助。

function DrawTextCentered(Canvas: TCanvas; const R: TRect; S: String): Integer;
var
  DrawRect: TRect;
  DrawFlags: Cardinal;
  DrawParams: TDrawTextParams;
begin
  DrawRect := R;
  DrawFlags := DT_END_ELLIPSIS or DT_NOPREFIX or DT_WORDBREAK or
    DT_EDITCONTROL or DT_CENTER;
  DrawText(Canvas.Handle, PChar(S), -1, DrawRect, DrawFlags or DT_CALCRECT);
  DrawRect.Right := R.Right;
  if DrawRect.Bottom < R.Bottom then
    OffsetRect(DrawRect, 0, (R.Bottom - DrawRect.Bottom) div 2)
  else
    DrawRect.Bottom := R.Bottom;
  ZeroMemory(@DrawParams, SizeOf(DrawParams));
  DrawParams.cbSize := SizeOf(DrawParams);
  DrawTextEx(Canvas.Handle, PChar(S), -1, DrawRect, DrawFlags, @DrawParams);
  Result := DrawParams.uiLengthDrawn;
end;

procedure TForm1.FormPaint(Sender: TObject);
const
  S = 'This is a very long text as test case for my paint routine.';
var
  R: TRect;
begin
  SetRect(R, 100, 100, 200, 140);
  Canvas.Rectangle(R);
  InflateRect(R, -1, -1);
  Caption := Format('%d characters drawn', [DrawTextCentered(Canvas, R, S)]);
end;

我看不出来deamon_x版本和这个版本的区别, 但是这个可以用!!! 谢谢 :) - Simon
这一行是关键:DT_END_ELLIPSIS或DT_NOPREFIX或DT_WORDBREAK或DT_EDITCONTROL或DT_CENTER; - Simon
2
我知道结果变得很简单,但是任何其他标志的组合都不起作用!如果可以的话,我会分配点数 :) - Simon
@NGLN,我希望你的示例可以解决我的问题,但实际上并没有。我试图在指定的矩形内垂直居中文本,但如果文本不适合并且绘制了省略号,则DrawRect.Bottom报告一个值,表示有3行,即使只有2行被清晰地绘制出来。这是一个显示问题的示例图像http://zoomplayer.com/pix/font_vcenter.jpg(文本后面较暗的区域是指定的矩形)。 - bLight
@bLight,我认为最好针对您的具体问题提出一个新的问题。 - NGLN

5

首先使用DT_CALCRECT测量文本。传递DT_WORDBREAK以启用换行,这将允许您找到所需文本的高度。然后在代码中计算垂直偏移量,以使文本垂直居中,并绘制到该偏移量。


我尝试了这种方法,但似乎在指定 DT_WORDBREAK 时忽略了 DT_WORD_ELLIPSIS。此例程当前不会在矩形之外绘制文本(也不显示“…”)。 - Simon
@Simon 使用 DT_WORDBREAK 后,所有文本都会被绘制。你看不到它可能是由于剪裁的原因。 - David Heffernan
1
@Simon DrawTextParams.uiLengthDrawn 返回绘制的字符数,包括由 DT_WORD_ELLIPSIS 引起的 3 个点。 - NGLN
2
@Simon - 我认为你正在寻找 DT_CENTER 或 DT_WORDBREAK 或 DT_END_ELLIPSIS 或 DT_MODIFYSTRING,这将使你的文本换行,水平居中并在文本末尾显示省略号,以防最后一行无法完全显示。 - user532231
1
你不需要使用 DT_MODIFYSTRING,它仅用于在绘制后处理文本。请使用 DT_EDITCONTROL 以仅显示完整可见行。如果不使用该选项,则会绘制部分行,这可能是看不到省略号的原因。 - NGLN
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接