Указание оконной процедуры для дочерней Windows

Я хотел бы знать, возможно ли указать WndProc для дочернего окна, созданного CreateWindowEx.

Я уже создал класс окна, главное окно, оконную процедуру и цикл сообщений. Код работает, и я решил оставить его для ясности моего вопроса.

Пока это мой Window Proc:

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        // Creation of the Win32 Window
        case WM_CREATE:
            // Add an Edit Field
            CreateWindowEx(
                WS_EX_CLIENTEDGE,
                "EDIT",
                "",
                WS_CHILD | WS_VISIBLE,
                5, 5, 200, 24,
                hwnd,
                (HMENU)100,
                g_Instance, // Comming from WinMain
                NULL
            );
            return DefWindowProc(hwnd, uMsg, lParam, wParam);
        case WM_KEYDOWN:
            // Track key presses on the edit field
            std::cout << "The key with the code " << wParam << " was pressed." << std::endl;
            return 0;
        case WM_PAINT:
            // Some painting code...
            return DefWindowProc(hwnd, uMsg, lParam, wParam);
        default:
            return DefWindowProc(hwnd, uMsg, lParam, wParam);
    }
}

Я ожидал, что нажатие клавиши в дочернем поле редактирования, которое я создал, вызовет сообщение WM_KEYDOWN, но этого не произошло! Ключи просто добавляются в поле редактирования в моем окне, но не вызывают сообщения WM_KEYDOWN.

Кажется, что созданное окно редактирования не использует мой WndProc. Как я могу это изменить?


person Vinz    schedule 05.06.2015    source источник


Ответы (2)


Ваш WndProc не получает WM_KEYDOWN сообщений, потому что, если пользователь печатает внутри элемента управления редактирования, это означает, что он имеет фокус (а не ваше окно), поэтому они отправляются в оконную процедуру элемента редактирования. , не твое. Однако процесс окна управления редактированием будет отправлять уведомления вашему WndProc (его процессу родительского окна).

Итак, если вы хотите реагировать только на то, что пользователь меняет содержимое вашего дочернего элемента управления, вам не нужна еще одна оконная процедура. Ваш текущий WndProc получит код уведомления EN_CHANGE в сообщении WM_COMMAND.

См. https://msdn.microsoft.com/en-us/library/windows/desktop/bb761676(v=vs.85).aspx


Если вы действительно хотите перехватить WM_KEYDOWN сообщений, вам нужно создать подкласс элемента управления редактирования, например:

OldWndProc = (WNDPROC)SetWindowLongPtr (hButton, GWLP_WNDPROC, (LONG_PTR)NewWndProc);

Вам также необходимо определить новую процедуру Windows (NewWndProc), которая должна обрабатывать сообщение WM_KEYDOWN (и любое другое сообщение, которое вы хотите обработать). Вам также необходимо вызвать OldWndProc так же, как вы бы вызвали DefWndProc в стандартном WndProc, если только вы не хотите, чтобы элемент управления редактированием выполнял свою обычную обработку.

Дополнительные сведения о подклассах см. в разделе https://msdn.microsoft.com/en-us/library/windows/desktop/bb773183(v=vs.85).aspx

Редактировать

Отвечая на комментарий ОП здесь.

Если ваше окно является диалоговым окном, вы должны быть уведомлены о клавише ввода в вашем WndProc:

 case WM_COMMAND:

      if(wParam=IDOFDEFBUTTON || IDOK) ...

См. https://support2.microsoft.com/Default.aspx?scid=kb;en-us;Q102589

Честно говоря, я никогда не тратил время на то, чтобы понять, что такое диалоговое окно на самом деле. Но если я правильно помню, вы можете заставить свое окно получать эти специальные уведомления, вызвав IsDialogMessage в своем насосе сообщений:

if(!IsDialogMessage(hWnd,&msg)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
 }

Интересную информацию о IsDialogMessage см. на http://blogs.msdn.com/b/oldnewthing/archive/2012/04/16/10293933.aspx

Если это не дает вам достаточного контроля, вам, вероятно, придется создать подкласс элемента управления редактирования.

person ThreeStarProgrammer57    schedule 05.06.2015
comment
Большое спасибо за подробный ответ. Итак, я вижу, что EN_CHANGE срабатывает, когда что-то происходит в дочернем элементе управления. Но есть ли способ узнать, ЧТО с ним произошло? Например, какая клавиша была нажата? Было бы очень удобно, если бы я мог справиться с нажатием клавиши Enter. Или мне нужно будет создать подкласс для этого? - person Vinz; 05.06.2015

Ваш вызов CreateWindowsEx создает новое окно с классом wnd «EDIT», имеющим собственную процедуру Window. Вам нужен новый WndProc и установите его во вновь созданное окно (чей дескриптор возвращается CreateWindowEx) через функцию SetClassLong.

person marom    schedule 05.06.2015