我正在尝试使用 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 行文本,破坏了垂直居中代码。
花了几年时间,但我终于找到了一个可行的解决方案,我希望这对某人有帮助。
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;