将 TRichEdit 绘制到画布上
我正在尝试在 Delphi XE 中实现一个支持 RTF 的工具提示窗口。为了呈现富文本,我使用了离屏 TRichEdit。我需要做两件事:
- 测量文本的大小。
- 绘制文本
为了完成这两项任务,我编写了这个方法:
procedure TLookupHintWindow.CallFormatRange(R: TRect; var Range: TFormatRange;
MustPaint: Boolean);
var
TextRect: TRect;
begin
RichText.SetBounds(R.Left, R.Top, R.Right, R.Bottom);
TextRect := Rect(0, 0,
RichText.Width * Screen.Pixelsperinch,
RichText.Height * Screen.Pixelsperinch);
ZeroMemory(@Range, SizeOf(Range));
Range.hdc := Canvas.Handle;
Range.hdcTarget := Canvas.Handle;
Range.rc := TextRect;
Range.rcpage := TextRect;
Range.chrg.cpMin := 0;
Range.chrg.cpMax := -1;
SendMessage(RichText.Handle, EM_FORMATRANGE,
NativeInt(MustPaint), NativeInt(@Range));
SendMessage(RichText.Handle, EM_FORMATRANGE, 0, 0);
end;
传入 Range 参数,因此我可以在该方法之外使用计算出的尺寸。 MustPaint 参数确定是否应计算范围 (False) 还是绘制范围 (True)。
为了计算范围,我将这种方法称为:
function TLookupHintWindow.CalcRichTextRect(R: TRect; const Rtf: string): TRect;
var
Range: TFormatRange;
begin
LoadRichText(Rtf);
CallFormatRange(R, Range, False);
Result := Range.rcpage;
Result.Right := Result.Right div Screen.PixelsPerInch;
Result.Bottom := Result.Bottom div Screen.PixelsPerInch;
// In my example yields this rect: (0, 0, 438, 212)
end;
绘制它:
procedure TLookupHintWindow.DrawRichText(const Text: string; R: TRect);
var
Range: TFormatRange;
begin
CallFormatRange(R, Range, True);
end;
问题是,虽然它计算出一个宽 438 像素、高 212 像素的矩形,但它实际上绘制的矩形非常宽(被剪裁)且只有 52 像素高。
我打开了自动换行,尽管我的印象是不需要这样做。
有什么想法吗?
I'm trying to implement an RTF-capable tool tip window in Delphi XE. To render the rich text, I'm using an off-screen TRichEdit. I need to do two things:
- Measure the size of the text.
- Paint the text
To accomplish both tasks, I wrote this method:
procedure TLookupHintWindow.CallFormatRange(R: TRect; var Range: TFormatRange;
MustPaint: Boolean);
var
TextRect: TRect;
begin
RichText.SetBounds(R.Left, R.Top, R.Right, R.Bottom);
TextRect := Rect(0, 0,
RichText.Width * Screen.Pixelsperinch,
RichText.Height * Screen.Pixelsperinch);
ZeroMemory(@Range, SizeOf(Range));
Range.hdc := Canvas.Handle;
Range.hdcTarget := Canvas.Handle;
Range.rc := TextRect;
Range.rcpage := TextRect;
Range.chrg.cpMin := 0;
Range.chrg.cpMax := -1;
SendMessage(RichText.Handle, EM_FORMATRANGE,
NativeInt(MustPaint), NativeInt(@Range));
SendMessage(RichText.Handle, EM_FORMATRANGE, 0, 0);
end;
The Range parameter is passed in, so I can use the calculated dimensions outside this method. The MustPaint parameter determines if the range should be calculated (False) or painted (True).
To calculate the range, I call this method:
function TLookupHintWindow.CalcRichTextRect(R: TRect; const Rtf: string): TRect;
var
Range: TFormatRange;
begin
LoadRichText(Rtf);
CallFormatRange(R, Range, False);
Result := Range.rcpage;
Result.Right := Result.Right div Screen.PixelsPerInch;
Result.Bottom := Result.Bottom div Screen.PixelsPerInch;
// In my example yields this rect: (0, 0, 438, 212)
end;
To paint it:
procedure TLookupHintWindow.DrawRichText(const Text: string; R: TRect);
var
Range: TFormatRange;
begin
CallFormatRange(R, Range, True);
end;
The problem is that while it calculates a rectangle that is 438 pixels wide and 212 high, it actually paints one that is very wide (gets clipped) and only 52 pixels high.
I have word wrap turned on, although it was my impression that that should not be needed.
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的设备已关闭。请考虑代码中的此表达式,例如:
左侧项以像素为单位,右侧项以像素/英寸为单位,因此结果的单位为像素平方/英寸。
em_FormatRange
中使用的矩形的预期单位是缇。如果您想将像素转换为缇,您需要这个:您不需要屏幕外的丰富编辑控件。您只需要一个无窗口丰富编辑控件,您可以指示将其直接绘制到工具提示上。 我发布了一些 Delphi 代码,使基础知识变得简单。 请注意,它是不支持 Unicode,而且我也没有计划这样做(尽管它可能不会太复杂)。
我的代码中的主要函数是
DrawRTF
,如下所示,位于 RTFPaint.pas 中。但它不太符合您的需求;您想在绘制之前发现尺寸,而我的代码假设您已经知道绘制目标的尺寸。要测量 RTF 文本的大小,请调用ITextServices。 TxGetNaturalSize
。自动换行很重要。如果没有它,控件将假定它具有无限的宽度,并且只有在 RTF 文本请求时才会开始新行。
Your units are off. Consider this expression from your code, for example:
The left term is in pixels, and the right term is in pixels/inch, so the units of the result are pixels²/inch. The expected unit for the rectangles used in
em_FormatRange
is twips. If you want to convert pixels to twips, you need this:You don't need an off-screen rich-edit control. You just need a windowless rich-edit control, which you can instruct to paint directly onto your tool-tip. I've published some Delphi code that makes the basics straightforward. Beware that it's not Unicode-aware, and I have no plans to make it so (although it might not be too complicated to do).
The main function from my code is
DrawRTF
, shown below, in RTFPaint.pas. It doesn't quite fit your needs, though; you want to discover the size before drawing it, whereas my code assume you already know the dimensions of the drawing target. To measure the size of the RTF text, callITextServices.TxGetNaturalSize
.Word wrapping is important. Without it, the control will assume it has infinite width to work with, and it will only start a new line when the RTF text requests it.