Окно C ++ теряет фокус при нажатии дочерней кнопки

Я пытаюсь запустить графический интерфейс для приложения C ++, но у меня проблема с событиями нажатия клавиш. В принципе, все работает нормально, пока я не нажимаю никакие кнопки (главное окно регистрирует ключевые события), но как только я нажимаю кнопку, главное окно теряет фокус и больше не фиксирует ключевые события. Это может быть глупый вопрос, но я новичок в C ++. Это часть кода, который я использую:

Создание главного окна:

hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szClassName,         /* Classname */
               "Application Name",  /* Title Text */
               WS_OVERLAPPEDWINDOW, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               540,                 /* The programs width */
               250,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /* No menu */
               hThisInstance,       /* Program Instance handler */
               NULL                 /* No Window Creation data */
           );

Создание одной из кнопок:

CreateWindow(TEXT("button"), TEXT("Start"),
                 WS_VISIBLE | WS_CHILD,
                 x, y, width, height,
                 hwnd, (HMENU) 6, NULL, NULL);

Я также заметил, что всякий раз, когда я нажимаю кнопку, запускается событие WM_KILLFOCUS, поэтому я думаю, что это проблема с фокусом. Я также попытался захватить событие WM_KILLFOCUS, а затем снова установить фокус с помощью SetActiveWindow, но это привело к сбою моей программы.

Любая помощь будет оценена по достоинству :)


person npinti    schedule 15.12.2011    source источник
comment
Являются ли кнопки частью главного окна, и кто тогда получает фокус? Или вы создаете диалог с кнопками, и когда вы нажимаете кнопку в диалоге, диалог получает фокус?   -  person PlasmaHH    schedule 15.12.2011
comment
У меня только одно главное окно с кнопками. Я создаю окно и кнопки в предоставленном коде, я не создаю никаких диалогов. Я не знаю, кто получает фокус, поскольку каждая кнопка кажется окном, я предполагаю, что как только я нажимаю на кнопку, кнопка получает фокус.   -  person npinti    schedule 15.12.2011
comment
Я не могу этого понять: (HMENU) 6 Зачем это нужно?   -  person Murali Krishna    schedule 15.12.2011
comment
Это позволит мне определить, какая кнопка была нажата в функции WindowProcedure. Я пробовал передать всего 6, но это вызывает следующую ошибку: недопустимое преобразование из int в HMENU__ | ошибка: инициализация аргумента 10 'HWND__ CreateWindowExA (DWORD, const CHAR *, const CHAR *, DWORD, int, int, int, int, HWND__ , HMENU__, HINSTANCE__ , недействительно) '|   -  person npinti    schedule 15.12.2011


Ответы (3)


Оказалось, что я использовал не ту функцию (SetWindowActive). Ответ Асафа Леви показался мне сложным, и я подумал, что может быть другой способ обойти это. Мне удалось найти функцию SetFocus, которая дает фокус любому заданному окну, предоставляя ему его дескриптор.

Чтобы заставить его работать, мне нужно было сделать следующее: как только необходимый код будет выполнен в блоке WM_COMMAND, я вызвал функцию SetFocus с дескриптором главного окна. Это вернуло фокус главному окну и позволило ему получать события.

Обратите внимание: размещение SetFocus в блоке WM_KILLFOCUS приведет к тому, что кнопки и любой другой компонент в нем перестанут реагировать на события.

person npinti    schedule 15.12.2011
comment
Я рад, что вы нашли более короткий путь, меньше кода = лучший код :) - person Assaf Levy; 15.12.2011
comment
Обратите внимание, что принудительное возвращение фокуса к кадру означает, что вы не можете дважды щелкнуть кнопку, дважды нажав пробел. Более традиционный способ сделать это - использовать метод IsDialogMessage. Почему вам нужно постоянно отвлекать внимание от того места, где его поставил пользователь? - person Raymond Chen; 15.12.2011
comment
Потому что, если главное окно теряет фокус, я больше не могу захватывать события нажатия клавиш из главного окна. - person npinti; 15.12.2011

Это сделано намеренно. Главное окно - это window, но поэтому кнопка - это window, и только одна из них может иметь фокус в любой момент времени. Если вы не хотите, чтобы кнопка «украла» фокус, добавьте обработчик OnFocus (или перехват WM_SETFOCUS) и немедленно верните фокус в предыдущее окно (я считаю, что это находится в WPARAM из WM_SETFOCUS).

Легкий взлом:

  1. hMyButton = CreateWindow («кнопка», ...).
  2. Определите функцию MyButtonProc (HWND, UINT, WPARAM, LPARAM).
  3. Вызов SetWindowLong (hMyButton, GWL_WNDPROC, (LONG) MyButtonProc). Сохраните значение, возвращаемое этой функцией, в g_OldButtonProc.
  4. Внутри MyButtonProc () перехватите WM_SETFOCUS и вызовите SetFocus (hMyMainWindow). Всегда возвращайте CallWindowProc (h_OldButtonProc, hwnd, msg, ...) в конце вашей функции MyButtonProc (), если только сообщение не было WM_SETFOCUS.

Это поможет (проверено).

person Assaf Levy    schedule 15.12.2011
comment
Да, я так и думал, поскольку в основном одна и та же функция используется для создания как окна, так и кнопки. Приветствуются любые дальнейшие разъяснения :) - person npinti; 15.12.2011
comment
Мне удалось найти способ обойти это, будучи новичком в C ++, я нашел ваш ответ слишком сложным для меня. Тем не менее, большое спасибо за понимание :) - person npinti; 15.12.2011

Первый ответ был частично точным. Создание подкласса кнопки может избавить от проблемы; однако обработка WM_SETFOCUS, будь то в родительском окне или в процедуре подкласса, или в BN_SETFOCUS, приведет к зависанию пользовательского интерфейса, если вы возьмете фокус с кнопки.

Что вы должны переопределить в процедуре подкласса, так это WM_LBUTTONUP. Поскольку к тому моменту, когда вы отпускаете кнопку мыши, вы уже нажали кнопку Windows.

Заметьте, я считаю, что это полная чушь для кнопки, которая крадет фокус. Должен быть стиль типа BS_NO_STEAL_FOCUS, который предотвращает это. Поскольку это очень громоздко, когда вы хотите, чтобы другое окно обрабатывало нажатия клавиш или прокрутку.

/** Procedure for subclass. 
      This procedure is called first for the widget/control.
      Unhandled or partially handled message can goes to
      original procedure by calling DefSubclassProc(...).
      buttonProcEx takes all four params of normal procedure, plus a
       param for user defined object. 
      Note this is what win32 should have done in the first place.
 */
LRESULT CALLBACK buttonProcEx(HWND hwnd,uint msg,WPARAM,LPARAM,DWORD_PTR)
{
    if(msg == WM_LBUTTONUP) 
    {
     setFocus(GetParent(hwnd));
     return 0; //do not allow default behaviour
    }
    else return DefSubclassProc(hwnd,msg,wparam,lparam);
}


//Call this after creating your button

SetWindowSubclass ((HWND) кнопка, buttonProcEx, 0, NULL);

or

struct Content {...}content; //lifetime should be long enough
SetWindowSubclass((HWND)button,buttonProcEx,0,(DWORD_PTR)&content);
person user13947194    schedule 09.06.2021