Delphi 11中TRichEdit在画布与打印机画布渲染尺寸不一致的解决方法
TRichEdit屏幕渲染与打印尺寸一致的解决方法
问题背景
我基于Delphi 11、Windows 10开发应用,使用以下代码将TRichEdit组件内容渲染到图像画布或打印机画布:
procedure TmainForm.printRTF(RE : TRichEdit; aRect : TRect);// aRect calculated with ppi=127 var fmt : TFormatRange; res : integer; begin // aCanvas is Image.canvas or printer.canvas // and aRect represents a frame in which I want to render the TRichEdit // and for the screen is calculated with ppi=127 to print in real size as on printer aCanvas.polygon(aRect); // It draws the exactly same frame both screen/printer RE.lines.LoadFromFile(RTFfileName); with fmt do begin HDC := aCanvas.Handle; hdcTarget := HDC; if aCanvas = Image.canvas then res := pixelsPerInch else res := PrnResX; // printer's resolution rc.left := round(aRect.left*1440/res); rc.top := round(aRect.top *1440/res); rc.right:= round(aRect.right*1440/res); rc.bottom := round(aRect.bottom*1440/res); rcPage := rc; chrg.cpMin := 0; chrg.cpMax := -1; SetBkMode(aCanvas.Handle, OPAQUE); RE.Perform(EM_FORMATRANGE, 0, integer(@fmt)); RE.Perform(EM_FORMATRANGE, 1, integer(@fmt)); RE.Perform(EM_FORMATRANGE, 0, 0); end; end;
实际测试发现:屏幕上渲染的文本尺寸为W=140mm、H=70mm,但渲染到打印机画布后尺寸为W=180mm、H=90mm——这个打印尺寸和Word中以130%缩放显示A4实际大小的文本尺寸一致。推测TRichEdit默认采用96ppi的逻辑分辨率,而非屏幕127ppi的物理分辨率,导致屏幕显示和打印尺寸不匹配。
问题根源
TRichEdit依赖Windows原生RichEdit控件,默认使用96 DPI的传统系统逻辑分辨率进行排版计算,即使屏幕物理DPI为127,它的排版逻辑仍按96ppi处理,导致屏幕渲染的尺寸比实际打印尺寸小(127/96≈1.32,和130%缩放比例吻合)。要让屏幕显示与打印尺寸一致,必须让TRichEdit在屏幕渲染时,基于屏幕物理DPI来计算排版参数。
解决方法
核心修改两点:
- 屏幕渲染时,获取屏幕实际物理DPI,替代默认的96ppi参数
- 确保
TFormatRange的rc参数转换时,使用实际DPI计算,对齐打印的排版逻辑
修改后的代码
procedure TmainForm.printRTF(RE : TRichEdit; aRect : TRect); // aRect calculated with ppi=127 var fmt : TFormatRange; res : integer; ScreenDC: HDC; begin aCanvas.polygon(aRect); // 屏幕和打印机上的框尺寸保持一致 RE.lines.LoadFromFile(RTFfileName); with fmt do begin HDC := aCanvas.Handle; hdcTarget := HDC; if aCanvas = Image.canvas then begin // 获取屏幕物理DPI,替换默认的96ppi ScreenDC := GetDC(0); try res := GetDeviceCaps(ScreenDC, LOGPIXELSX); // 获取屏幕水平物理DPI finally ReleaseDC(0, ScreenDC); end; end else res := PrnResX; // 使用打印机分辨率 // 按实际DPI将aRect转换为twips单位(1英寸=1440 twips) rc.left := Round(aRect.Left * 1440 / res); rc.top := Round(aRect.Top * 1440 / res); rc.right := Round(aRect.Right * 1440 / res); rc.bottom := Round(aRect.Bottom * 1440 / res); rcPage := rc; chrg.cpMin := 0; chrg.cpMax := -1; SetBkMode(aCanvas.Handle, OPAQUE); // 执行排版计算与渲染 RE.Perform(EM_FORMATRANGE, 0, Integer(@fmt)); RE.Perform(EM_FORMATRANGE, 1, Integer(@fmt)); RE.Perform(EM_FORMATRANGE, 0, 0); // 清理资源 end; end;
额外注意事项
- 开启高DPI感知:确保Delphi项目已开启高DPI支持,否则
GetDeviceCaps可能仍返回96。在Delphi 11中,进入项目选项 -> Application -> Manifest,勾选"Enable high DPI support",并选择"Per Monitor v2"模式。 - 验证效果:修改后,屏幕上渲染的文本尺寸将与打印尺寸一致,和Word中100%实际大小显示的文本尺寸匹配。
内容的提问来源于stack exchange,提问作者user3140961
相关产品推荐
相关产品推荐

