【问题标题】:EM_SETSEL swaps parametersEM_SETSEL 交换参数
【发布时间】:2012-01-04 10:46:49
【问题描述】:

我使用 EM_SETSEL 消息在编辑控件中选择文本。我需要从末尾到中间选择一些文本,以便插入符号位置在文本的中间。 MSDN documentation 声明如下:

起始值可以大于结束值。两个值中的较低值指定选择中第一个字符的字符位置。较高的值指定第一个字符在所选内容之外的位置。

起始值是选择的锚点,结束值是活动端。如果用户使用 SHIFT 键调整选择的大小,则活动端可以移动,但锚点保持不变。

但似乎较小的价值总是成为锚,例如我无法实现预期的行为。

代码示例(其中“父级”为 CWnd*):

TRACE("EM_SETSEL(%d, %d)\n", pos1, pos2);
parent->SendMessage(EM_SETSEL, pos1, pos2);
parent->SendMessage(EM_GETSEL, (WPARAM)&pos1, (LPARAM)&pos2);
TRACE("EM_GETSEL(%d, %d)\n", pos1, pos2);

产生输出:

EM_SETSEL(5, 1)
EM_GETSEL(1, 5)

还有其他方法可以获得所需的选择吗?

【问题讨论】:

  • 没有。 EDIT 控件不区分从右到左选择从左到右。 Which means for one thing that you can't get the caret position accurately when a selection is active.

标签: c++ winapi


【解决方案1】:

关于 EM_GETSEL/EM_SETSEL:

  • EM_GETSEL 检索左/右位置
  • EM_SETSEL 设置锚点/活动位置

EM_SETSEL 使用锚点/活动位置,使您可以轻松地将插入符号放置在选择的左侧/右侧,所以我不确定为什么在另一个答案中使用了 kludge。

EM_GETSEL 是笨拙的窗口消息,为此需要拼凑。这个 kludge 暂时将选择更改为 0 个字符,以便检索活动位置,但是,当我使用它时,我没有看到任何明显的变化。

检索锚点/活动位置:

  • 使用 EM_GETSEL 检索左/右位置
  • 使用 EM_SETSEL 将选择临时设置为 0 个字符,将插入符号留在活动位置
  • 使用 EM_GETSEL 检索活动位置
  • 使用 EM_SETSEL 恢复原始选择

一些用于设置选择的示例 AutoHotkey 代码:

q:: ;Notepad - set active position (caret) at right
PostMessage, 0xB1, 5, 10, Edit1, A ;EM_SETSEL := 0xB1
return

w:: ;Notepad - set active position (caret) at left
PostMessage, 0xB1, 10, 5, Edit1, A ;EM_SETSEL := 0xB1
return

一些用于获取/设置选择的 AutoHotkey 函数示例:

JEE_EditGetRange(hCtl, ByRef vPos1, ByRef vPos2)
{
    VarSetCapacity(vPos1, 4), VarSetCapacity(vPos2, 4)
    SendMessage, 0xB0, % &vPos1, % &vPos2,, % "ahk_id " hCtl ;EM_GETSEL := 0xB0 ;(left, right)
    vPos1 := NumGet(&vPos1, 0, "UInt"), vPos2 := NumGet(&vPos2, 0, "UInt")
}

;==================================================

JEE_EditSetRange(hCtl, vPos1, vPos2, vDoScroll:=0)
{
    SendMessage, 0xB1, % vPos1, % vPos2,, % "ahk_id " hCtl ;EM_SETSEL := 0xB1 ;(anchor, active)
    if vDoScroll
        SendMessage, 0xB7, 0, 0,, % "ahk_id " hCtl ;EM_SCROLLCARET := 0xB7
}

;==================================================

;note: although this involves deselecting and selecting it seems to happen invisibly
JEE_EditGetRangeAnchorActive(hCtl, ByRef vPos1, ByRef vPos2)
{
    ;get selection
    VarSetCapacity(vPos1, 4), VarSetCapacity(vPos2, 4)
    SendMessage, 0xB0, % &vPos1, % &vPos2,, % "ahk_id " hCtl ;EM_GETSEL := 0xB0
    vPos1 := NumGet(&vPos1, 0, "UInt"), vPos2 := NumGet(&vPos2, 0, "UInt")
    if (vPos1 = vPos2)
        return
    vPos1X := vPos1, vPos2X := vPos2

    ;set selection to 0 characters and get active position
    SendMessage, 0xB1, -1, 0,, % "ahk_id " hCtl ;EM_SETSEL := 0xB1
    VarSetCapacity(vPos2, 4)
    SendMessage, 0xB0, % &vPos2, 0,, % "ahk_id " hCtl ;EM_GETSEL := 0xB0
    vPos2 := NumGet(&vPos2, 0, "UInt")

    ;restore selection
    vPos1 := (vPos2 = vPos2X) ? vPos1X : vPos2X
    SendMessage, 0xB1, % vPos1, % vPos2,, % "ahk_id " hCtl ;EM_SETSEL := 0xB1 ;(anchor, active)
}

链接:

我最初在 AutoHotkey 论坛上发布的上述功能:
GUI 命令:完成重新思考 - AutoHotkey 社区
https://autohotkey.com/boards/viewtopic.php?f=5&t=25893&p=138292#p138292

【讨论】:

    【解决方案2】:

    @vafylec 的回答很好。我这里刚刚重写了Delphi,比AHK更容易解析和翻译成其他语言。

    基本上,EM_SETSEL 允许您将锚点设置在范围的任一端,但EM_GETSEL 只返回第一个和最后一个字符,丢失了该信息。只需一点点,您就可以解决这个问题:

    procedure GetEditSelection(Handle: THandle; var Anchor, Start, Finish: Integer);
    begin
      SendMessage(Handle, EM_GETSEL, NativeUInt(@Start), NativeUInt(@Finish));
      SendMessage(Handle, EM_SETSEL, -1, 0);
      SendMessage(Handle, EM_GETSEL, NativeUInt(@Anchor), 0);
      if Anchor = Start then 
        SendMessage(Handle, EM_SETSEL, Finish, Start)
      else
        SendMessage(Handle, EM_SETSEL, Start, Finish);
    end;
    

    【讨论】:

      猜你喜欢
      • 2013-11-10
      • 2011-03-17
      • 1970-01-01
      • 1970-01-01
      • 2012-11-16
      • 2012-03-03
      • 2019-11-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多