【问题标题】:Win32 API: How to catch escape key in Edit control?Win32 API:如何在编辑控件中捕获转义键?
【发布时间】:2014-02-16 23:44:58
【问题描述】:

我发现当焦点位于Edit control 时,出于某种未知原因,Escape 键永远不会产生消息。 下面是创建父窗口的代码,并在其上方编辑控件。在 MyCallBckProcedure() 中,我将 printf() 放在 *WM_COMMAND* 下,以捕获由 Edit 生成的消息。更重要的是——我什至尝试打印 MyCallBckProcedure() 中捕获的所有消息;但如果专注于 Edit,则转义键永远不会产生任何消息。 这里会出现什么奇怪的问题?

#include <iostream>
#include <windows.h>
#include <stdio.h>

#define IDC_MAIN_EDIT 101

LRESULT __stdcall MyCallBckProcedure( HWND window, unsigned msg, WPARAM wp, LPARAM lp ){
    printf("%x ",msg);
    switch(msg){
        case WM_COMMAND://here should be catched the escape key of Edit
            printf("%x ",msg);
            break;
        case WM_KEYDOWN:
            printf("%x ",msg);
            if(wp == VK_ESCAPE)PostQuitMessage(0);
            break;
        case WM_DESTROY:
            std::cout << "\ndestroying window\n" ;
            PostQuitMessage(0);
            return 0;
        default:
            return DefWindowProc( window, msg, wp, lp ) ;

        break;
        case WM_SIZE:{
            HWND hEdit;
            RECT rcClient;

            GetClientRect(window, &rcClient);

            hEdit = GetDlgItem(window, IDC_MAIN_EDIT);
            SetWindowPos(hEdit, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER);
        }
        break;
    }
}

int main(){
    const char* const myclass = "myclass";
    WNDCLASSEX wndclass = { sizeof(WNDCLASSEX), CS_DBLCLKS, MyCallBckProcedure,
                            0, 0, GetModuleHandle(0), LoadIcon(0,IDI_APPLICATION),
                            LoadCursor(0,IDC_ARROW), HBRUSH(COLOR_WINDOW+1),
                            0, myclass, LoadIcon(0,IDI_APPLICATION) };
    if(RegisterClassEx(&wndclass)<0){
        printf("ERR: in registering window class\n");
        return 1;
    }
    //Creating window
    HWND window = CreateWindowEx( 0, myclass, "title",
                   WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
                   CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, GetModuleHandle(0), 0 );
    if(!window){
        printf("ERR: in creating window\n");
        return 1;
    }
    ShowWindow( window, SW_SHOWDEFAULT );
    MSG msg;
    //creating TextBox on the window
    HFONT hfDefault;
    HWND hEdit;
    hEdit = CreateWindowEx(0, "edit", "", 
        WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        window, (HMENU)IDC_MAIN_EDIT, GetModuleHandle(NULL), NULL);
    if(hEdit == NULL){
        MessageBox(window, "Could not create edit box.", "Error", MB_OK | MB_ICONERROR);
        return 1;
    }
    hfDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
    SendMessage(hEdit, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0));
    //Now resize TextBox to fill whole parent window
    RECT RectSize;
    GetClientRect(window,&RectSize);
    hEdit = GetDlgItem(window,IDC_MAIN_EDIT);
    SetWindowPos(hEdit, 0,0,0,RectSize.right,RectSize.bottom,SWP_NOZORDER);
    //Process messages
    while(GetMessage(&msg,0,0,0) ){
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

【问题讨论】:

  • WM_GETDLGCODE 是您正在寻找的。​​span>

标签: c++ winapi


【解决方案1】:

在 Edit 处于焦点时按 ESC 不会向 Edit 的父窗口生成 WM_COMMAND 消息。它会向编辑窗口本身生成WM_KEYDOWNWM_KEYUPWM_CHARWM_UNICHAR 消息。

更新:您只处理发往父窗口的消息。您需要将消息过程分配给编辑窗口,例如:

WNDPROC lpEditWndProc;

LRESULT CALLBACK MyEditCallBckProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if( (uMsg == WM_CHAR) && (wParam == VK_ESCAPE) )
    {
        PostQuitMessage(0);
        return 0;
    }
    return CallWindowProc(lpEditWndProc, hWnd, uMsg, wParam, lParam);
}

...

HWND hEdit = CreateWindowEx(...);
#ifdef _WIN64
lpEditWndProc = (WNDPROC) SetWindowLongPtr(hEdit, GWLP_WNDPROC, (LONG_PTR)&MyEditCallBckProcedure);
#else
lpEditWndProc = (WNDPROC) SetWindowLongPtr(hEdit, GWL_WNDPROC, (LONG_PTR)&MyEditCallBckProcedure);
#endif

或者:

LRESULT CALLBACK MyEditCallBckProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    if( (uMsg == WM_CHAR) && (wParam == VK_ESCAPE) )
    {
        PostQuitMessage(0);
        return 0;
    }
    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

...

HWND hEdit = CreateWindowEx(...);
SetWindowSubclass(hEdit, &MyEditCallBckProcedure, 0, 0);

【讨论】:

  • 我刚刚将行 while(GetMessage(&amp;msg,0,0,0) ) 更改为 while(GetMessage(&amp;msg,hEdit,0,0) ) 以获取来自 Edit 的消息。它仍然没有产生任何东西。
  • 我不是这个意思。您已将MyCallBckProcedure() 分配给您的myclass 窗口,因此它只会接收专门针对您的myclass 窗口的消息。要为您的edit 窗口接收消息,您需要使用SetWindowLong/Ptr(GWL_WNDPROC) 为您的hEdit 变量分配一个单独的函数
  • 谢谢!虽然光标消失了,但我认为这是小事。非常感谢!
  • 建议的解决方案帮助我修复了模块中的 ESC 按键退出问题
猜你喜欢
  • 1970-01-01
  • 2013-12-11
  • 1970-01-01
  • 2011-11-15
  • 1970-01-01
  • 2010-12-29
  • 2011-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多