使用WinAPI的“DrawText”函数绘制垂直居中的多行字符串

问题描述 投票:0回答:1

我正在尝试使用 WinAPI 的 DrawText 函数在位图中垂直和水平居中绘制一个自动换行的字符串。

问题是,如果文本长于可用空间,并且“END ELLIPSIS”(...)被添加到裁剪后的字符串中,则使用“DT_CALCRECT”时返回的报告绘图坐标会报告未裁剪的行数,这会与垂直居中计算。

我读了很多关于此的文章,并认为“Delphi - 在矩形中心绘制文本多行”可能包含答案,但事实并非如此(使用链接问题中的示例的代码输出的屏幕截图 http://zoomplayer.com/pix/font_vcenter.jpg)。已接受答案的作者建议我创建一个新问题,所以就在这里。

为了快速参考,这里有一个稍微简化的(删除不相关的代码)文本渲染代码,来自链接的接受答案:

procedure DrawTextCentered(Canvas: TCanvas; const R: TRect; S: String);
var
  DrawRect: TRect;
  DrawFlags: Cardinal;
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;
  DrawTextEx(Canvas.Handle, PChar(S), -1, DrawRect, DrawFlags, nil);
end;

从屏幕截图中可以看出,问题是在使用“DT_CALCRECT”标志初始调用 DrawText 来测量输出高度以供以后垂直居中之后,渲染字符串“Trending in: Worldwide”返回一个 DrawRect.Bottom 值,表示尽管只绘制了 2 行,但仍显示 3 行文本,破坏了垂直居中代码。

windows winapi
1个回答
0
投票

花了几年时间,但我终于找到了一个可行的解决方案,我希望这对某人有帮助。

function DrawVerticalCenteredText(Canvas: TCanvas; const Text: WideString; X, Y, Width, Height, Flags : Integer): Integer;
var
  DrawRect   : TRect;
  cRect      : TRect;
  Format     : UINT;
  fontHeight : Integer;
  fontLines  : Integer;
begin
  cRect      := Bounds(X, Y, Width, Height);
  DrawRect   := cRect;

  fontHeight := Canvas.TextHeight('0');
  fontLines  := Trunc(Height / fontHeight);

  Format     := DT_WORDBREAK or DT_NOPREFIX or DT_END_ELLIPSIS or DT_EDITCONTROL or Flags;

  // Calculate text height and modify string if necessary
  DrawTextExW(Canvas.Handle, PWideChar(Text), -1, DrawRect, Format or DT_CALCRECT, nil);

  DrawRect.Right := cRect.Right;
  if DrawRect.Bottom < cRect.Bottom then
  Begin
    OffsetRect(DrawRect, 0, (cRect.Bottom - DrawRect.Bottom) shr 1);
  End
    else
  Begin
    If DrawRect.Bottom <> cRect.Bottom then
    Begin
      DrawRect.Top := cRect.Top+((Height-(fontHeight*fontLines)) shr 1);
      DrawRect.Bottom := cRect.Bottom;
    End;
  End;

  // Draw the text
  Result := DrawTextExW(Canvas.Handle, PWideChar(Text), -1, DrawRect, Format, nil);
end;
© www.soinside.com 2019 - 2024. All rights reserved.