You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

额外注意事项

  1. 开启高DPI感知:确保Delphi项目已开启高DPI支持,否则GetDeviceCaps可能仍返回96。在Delphi 11中,进入项目选项 -> Application -> Manifest,勾选"Enable high DPI support",并选择"Per Monitor v2"模式。
  2. 验证效果:修改后,屏幕上渲染的文本尺寸将与打印尺寸一致,和Word中100%实际大小显示的文本尺寸匹配。

内容的提问来源于stack exchange,提问作者user3140961

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 01:42:50