【问题标题】:Select all text in edit contol by clicking Ctrl+A通过单击 Ctrl+A 选择编辑控件中的所有文本
【发布时间】:2012-04-12 15:43:06
【问题描述】:

如何通过按Ctrl+A来选择编辑控件中的所有文本? 我可以在 WndProc 中为父窗口捕获 Ctrl+A。 但我不知道如何捕捉应用于编辑控制的 ctrl+a 。 我也尝试使用加速器,但它再次仅适用于父窗口。 谢谢。 编辑:第一最简单的方法 此方法基于@phord 在此问题中的回答: win32 select all on edit ctrl (textbox)

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{ 
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        if (msg.message == WM_KEYDOWN && msg.wParam == 'A' && GetKeyState(VK_CONTROL) < 0)
    {
        HWND hFocused = GetFocus();
        wchar_t className[6];
        GetClassName(hFocused, className, 6);
        if (hFocused && !wcsicmp(className, L"edit"))
            SendMessage(hFocused, EM_SETSEL, 0, -1);
    }
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
}

编辑:第二种方法 需要使用 CreateAcceleratorTable + TranslateAccelerator 函数:

//全局变量:

enum {ID_CTRL_A = 1};
HACCEL accel;

//主程序

ACCEL ctrl_a;
ctrl_a.cmd = ID_CTRL_A; // Hotkey ID
ctrl_a.fVirt = FCONTROL | FVIRTKEY;
ctrl_a.key = 0x41; //'A' key
accel = CreateAcceleratorTable(&ctrl_a, 1); //we have only one hotkey

//GetMessage 循环的样子

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{ 
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        if (!TranslateAccelerator(hWnd, accel,  &msg))
        {
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
        }
    }
}

//在 WndProc 中我们必须添加下一个案例

case WM_COMMAND:
{
    if (LOWORD(wParam) == ID_CTRL_A && HIWORD(wParam) == 1)
    {
        //on which control there was pressed Ctrl+A
        //there is no way of getting HWND through wParam and lParam
        //so we get HWND which currently has focus.
        HWND hFocused = GetFocus();
        wchar_t className[6];
        GetClassName(hFocused, className, 6);
        if (hFocudsed && !wcsicmp(className, L"edit"))
            SendMessage(hFocused, EM_SETSEL, 0, -1);
    }
}
break;
case WM_DESTROY:
{
   DestroyAcceleratorTable(accel);
   PostQuitMessage(0);
}
break;

如您所见,这非常简单。

【问题讨论】:

  • 我以为EDIT 控件会自动处理此问题
  • @DavidHeffernan 一些文件说如果 ES_MULTILINE ctrl+a 不起作用。但是我没有那个风格还是有问题。
  • 你看这个问题了吗? stackoverflow.com/questions/291792/…
  • @MikeKwan 是的。我认为在所有答案中,这个问题没有正确的答案。正确答案在这里。
  • @UnhandledException:这个答案实际上包含了您所写的内容。 stackoverflow.com/a/315720/712358

标签: winapi visual-c++


【解决方案1】:

无需处理 WM_KEYDOWN!我知道这里的大多数示例(以及 CodeProject 和许多其他地方)都说有,但它并不能解决每当出现未处理的 WM_CHAR 时产生的蜂鸣声。

试试这个:

LRESULT CALLBACK Edit_Prc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
  if(msg==WM_CHAR&&wParam==1){SendMessage(hwnd,EM_SETSEL,0,-1); return 1;}
  else return CallWindowProc((void*)WPA,hwnd,msg,wParam,lParam);
}

记得使用 WPA=SetWindowLong(...) 将 EDIT 控件子类化到此 Edit_Prc(),其中 WPA 是 CallWindowProc(...) 的窗口过程地址

【讨论】:

  • 谢谢,这对我来说效果最好。它消除了“哔”声,并选择了所有文本。我不明白为什么 wParam==1 与 Ctrl+A 匹配? 1 不是 SOH(标题的开始)吗?
  • 不客气。关于匹配值 1 的 Ctrl+A,我想我从未想过,我想我只是查看了事件的传入值并使用了它。 && 的另一面是为了防止它错误地将其他任何具有相同值的 wParam 匹配的可能性......无论如何,很高兴知道它在我自己可能扭曲的上下文之外工作。 :)
  • 你们都太年轻了 ;) 以前,Control- 是键的代码,映射到 ASCII 的低位范围 (^C=3, ^G=bell, ^ H=退格,...)
【解决方案2】:

首先更改编辑控件的WindowProc:

if (!(pEditProc = (WNDPROC)SetWindowLong(hEdit, GWL_WNDPROC, (LONG)&EditProc)))
{
    assert(false);
    return false;
}

然后在新窗口proc中,处理ctrl+a:

LRESULT CALLBACK EditProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    if (msg == WM_KEYDOWN) {
        if (GetKeyState(VK_CONTROL) & 0x8000 && wParam == 'A') {
            SendMessage(hwnd, EM_SETSEL, 0, -1);
        }
    }
    return CallWindowProc(pEditProc, hwnd, msg, wParam, lParam);
}

【讨论】:

  • 此功能按要求运行,但按 Ctrl+A 时仍有“哔”声。是否有其他消息要捕获/抑制以防止这种哔声?
【解决方案3】:

好消息!

似乎编辑控件(不是多行)现在在 Win10 上原生支持 Ctrl + A。

我当前的 Windows SDK 版本是 10.0.17763.0。

仅在使用纯 Windows API 创建的简单 GUI APP 上进行测试。

MFC APP 应该有相同的结果。

测试二进制平台为x86,操作系统为Win10 x64。

【讨论】:

  • @BugHunterUK 就我而言,清单是必须的,以使其生效。我的 Win10 中有两个示例(Ctrl + A 有效 / Ctrl + A 无效)。
【解决方案4】:

菜鸟证明版?

我也使用加速器表编写了自己的版本。 这稍微清除了 WinMain,我试图让一切都尽可能地证明 n00b (因为我是其中之一)。 由于不需要枚举,因此也省略了枚举。

如前所述,我只是使用 winapi 的初学者,所以请务必 如果我错了,请纠正我。

在“Resource.h”中我定义了两个 ID 一个用于我们将使用的加速器表, 还有一个用于我们将使用的 selectall 命令。

Resource.h 内部:

#define IDR_ACCEL1 101
#define ID_SELECT_ALL 9003

然后在资源文件里面(在vs2017中这是PROJECTNAME.rc) 我们定义加速器表。 项目名称.rc:

IDR_ACCEL1 ACCELERATORS
{
    0x41, ID_SELECT_ALL, VIRTKEY, CONTROL // ctrl-A
}

说明

0x41 是 virtkey 'a'。

ID_SELECT_ALL(将是命令的 ID,这应该是我们在 Resource.h 文件中定义的 ID。

VIRTKEY 关键字指示应将 0x41 解释为虚拟键。

CONTROL 是将 a 与 (ctrl+a) 组合所需的修饰符。

然后在WinMain函数里面加载加速器:

HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCEL1));
if (hAccel == NULL)
{
    MessageBox(NULL, _T("Failed to load accelerator table!"),_T("Error"), MB_OK | MB_ICONEXCLAMATION);
    return 0;
}

注意:在尝试定义 hAccel 后,我们会检查是否已分配有效句柄。 虽然这不是必需的,但我相信这是更好的约定。

之后我们将 TranslateAccelerator 函数添加到消息循环中,这样就可以在窗口过程中处理命令了:

BOOL bRet;
while (bRet = GetMessage(&Msg, NULL, 0, 0) > 0)
{
    if (bRet == -1)
    {
        // Error handling can be done here.
    }
    else if (!TranslateAccelerator(hwnd, hAccel, &Msg))
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
}

最后进入Window过程 我们添加如下代码:

switch(msg)
{
    case WM_COMMAND:
       {
            switch (LOWORD(wParam))
            {
                case ID_SELECT_ALL:
                {
                    HWND hEdit;
                    hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT)  // Define IDC_MAIN_EDIT with an integer value in "Resource.h".
                }
                break;
            }
       break;
       }
}

注意:传递给 WM_COMMAND 的消息是我们为 ctrl+a 加速定义的 ID。

我希望这对 n00bies 有帮助。

【讨论】:

  • 您是否不需要 ID_SELECT_ALL 来实际选择文本,例如 SendMessage(hEdit , EM_SETSEL, 0, -1)?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-03
  • 2011-09-09
  • 1970-01-01
  • 2010-09-22
  • 1970-01-01
  • 2012-07-19
  • 1970-01-01
相关资源
最近更新 更多