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

Windows RichEdit拼写更正建议弹窗显示在错误显示器问题排查

双显示器下TRichEdit(RICHEDIT50W)拼写更正弹窗错位问题的成因与解决方法

成因

  1. DPI感知缺失:若应用未启用高DPI感知,当窗口处于不同DPI的双显示器环境时,系统会对窗口进行缩放,导致RichEdit控件的实际屏幕坐标计算错误,负责渲染拼写弹窗的系统文本服务框架(TSF)会基于错误坐标定位弹窗,最终出现在错误显示器上。
  2. TSF上下文未同步:RichEdit的拼写弹窗由TSF管理,当控件所在窗口在双显示器间移动或位置/大小变化时,控件未主动将最新的屏幕位置信息同步给TSF,导致TSF仍使用旧坐标计算弹窗位置。

解决方法

方法1:启用应用高DPI感知

在Delphi 10.3中开启高DPI支持:

  • 打开项目选项(Project > Options)
  • 切换到Application选项卡,找到Manifest设置
  • 勾选Enable runtime themes,在High DPI下拉菜单中选择Per Monitor v2或Per Monitor(根据目标系统版本选择)
  • 保存设置后重新编译应用

方法2:子类化RichEdit同步TSF上下文

通过子类化TRichEdit,在窗口位置/大小变化时强制刷新拼写检查配置,触发TSF同步控件最新位置:

unit MyRichEdit;

interface

uses
  Vcl.ComCtrls, Winapi.Messages, Winapi.Windows;

type
  TMyRichEdit = class(TRichEdit)
  private
    FSpellChecking: Boolean;
    FAutoCorrection: Boolean;
    procedure UpdateLangOptions;
  protected
    procedure WndProc(var Message: TMessage); override;
  public
    property SpellChecking: Boolean read FSpellChecking write FSpellChecking default True;
    property AutoCorrection: Boolean read FAutoCorrection write FAutoCorrection default True;
    constructor Create(AOwner: TComponent); override;
  end;

implementation

constructor TMyRichEdit.Create(AOwner: TComponent);
begin
  inherited;
  FSpellChecking := True;
  FAutoCorrection := True;
  UpdateLangOptions;
end;

procedure TMyRichEdit.UpdateLangOptions;
var
  Value: LRESULT;
const
  IMF_SPELLCHECKING = $0800;
  IMF_TKBAUTOCORRECTION = $2000;
begin
  Value := SendMessage(Handle, EM_GETLANGOPTIONS, 0, 0);
  
  if FSpellChecking then
    Value := Value or IMF_SPELLCHECKING
  else
    Value := Value and not IMF_SPELLCHECKING;

  if FAutoCorrection then
    Value := Value or IMF_TKBAUTOCORRECTION
  else
    Value := Value and not IMF_TKBAUTOCORRECTION;

  SendMessage(Handle, EM_SETLANGOPTIONS, 0, Value);
end;

procedure TMyRichEdit.WndProc(var Message: TMessage);
begin
  inherited;
  // 窗口位置或大小变化时,同步TSF上下文
  if (Message.Msg = WM_WINDOWPOSCHANGED) or (Message.Msg = WM_SIZE) then
    UpdateLangOptions;
end;

end.

使用时将原TRichEdit控件替换为TMyRichEdit即可。

方法3:手动通过TSF接口设置控件上下文

若前两种方法无效,可直接调用TSF接口同步控件屏幕位置:

uses
  ActiveX, Winapi.TSF, Winapi.Windows;

procedure UpdateRichEditSpellContext(ARichEdit: TRichEdit);
var
  pContext: ITfContext;
  pOwner: ITfContextOwner;
  Rect: TRect;
begin
  if SUCCEEDED(ARichEdit.Handle.QueryInterface(IID_ITfContextOwner, pOwner)) then
  begin
    if SUCCEEDED(pOwner.GetContext(pContext)) then
    begin
      GetWindowRect(ARichEdit.Handle, Rect);
      pContext.SetSelection(0, 0);
      pContext.SetTextExtent(@Rect, 1);
      pContext.Release;
    end;
    pOwner.Release;
  end;
end;

在RichEdit的OnEnter或OnResize事件中调用此函数,即可同步控件位置给TSF。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 23:47:34