Как включить вкладку и клавиши со стрелками с помощью python win32gui

Я создал несколько кнопок (окон) в главном окне, но вкладки и клавиши со стрелками не работают. Мое исследование показало, что для C++ использование IsDialogMessage в пересылке сообщений создает обход TranslateMessage/DispatchMessage следующим образом, чтобы обеспечить эту функциональность:

while(GetMessage(&Msg, NULL, 0, 0))
{
    if(!IsDialogMessage(g_hToolbar, &Msg))
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
}

Однако я использую python и модуль win32gui для CreateWindows и не могу понять, как обойти обычный захват сообщений, чтобы обеспечить естественную работу с клавиатурой. Мой код похож на этот:

from win32gui import *
from win32con import *

window_class = WNDCLASS()
hinst = window_class.hInstance = GetModuleHandle(None)
window_class.lpszClassName = 'ClassName'
window_class.style = CS_VREDRAW | CS_HREDRAW
window_class.hCursor = LoadCursor(0, IDC_ARROW)
window_class.hbrBackground = COLOR_WINDOW
window_class.lpfnWndProc = {}
classAtom = RegisterClass(window_class)

hwnd = CreateWindow(classAtom, "", WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION
                    | WS_SYSMENU | WS_MINIMIZEBOX | WS_EX_TOPMOST | WS_CLIPSIBLINGS,
                    0, 0, 140, 100, 0,  0, GetModuleHandle(None), None)
btn1_hwnd = CreateWindow("Button", "btn 1", WS_GROUP | WS_TABSTOP | WS_VISIBLE
                         | WS_CHILD | BS_DEFPUSHBUTTON | WS_CLIPSIBLINGS,
                         10, 10, 100, 20, hwnd, 0, GetModuleHandle(None), None)
btn2_hwnd = CreateWindow("Button", "btn 2", WS_GROUP | WS_TABSTOP | WS_VISIBLE
                         | WS_CHILD | BS_DEFPUSHBUTTON | WS_CLIPSIBLINGS,
                         10, 40, 100, 20, hwnd, 0, GetModuleHandle(None), None)

UpdateWindow(hwnd)
PumpMessages()

EDIT: С помощью этого кода создается окно с двумя кнопками, но невозможно переместить фокус с одной на другую, хотя они обе имеют флаг WS_TABSTOP.

Согласно спецификации MSDN IsDialogMessage приведенный выше фрагмент C++ является решением.

Когда IsDialogMessage обрабатывает сообщение, он проверяет сообщения клавиатуры и преобразует их в выборки для соответствующего диалогового окна. Например, клавиша TAB при нажатии выбирает следующий элемент управления или группу элементов управления, а клавиша СТРЕЛКА ВНИЗ при нажатии выбирает следующий элемент управления в группе.

Поскольку функция IsDialogMessage выполняет весь необходимый перевод и отправку сообщений, сообщение, обработанное IsDialogMessage, не должно передаваться в функцию TranslateMessage или DispatchMessage.

Итак, в основном вопрос: можно ли использовать IsDialogMessage из Python win2gui или есть какой-то обходной путь?


person mjpsr11    schedule 13.12.2015    source источник
comment
@zvone вы не предоставили воспроизводимый пример - classAtom не определен (здесь большой кусок кода), тогда ShowWindow не вызывается. TranslateMessage/DispatchMessage доступны в win32gui, так в чем же проблема?   -  person denfromufa    schedule 03.04.2016
comment
@denfromufa Я обновил вопрос. Обратите внимание, что PumpMessages можно заменить циклом GetMessage / TranslateMessage / DispatchMessage, но IsDialogMessage отсутствует, чтобы заставить его работать.   -  person zvone    schedule 03.04.2016


Ответы (2)


Я нашел пример CreateDialogIndirect используется на programcreek.com, что создает окно, подобное один из вопроса, с работающими вкладками. Вот он, немного измененный:

import win32con
import win32gui
import win32api

parent_hwnd = None
msgs = {}
style=win32con.WS_BORDER|win32con.WS_VISIBLE|win32con.WS_CAPTION|win32con.WS_SYSMENU  ## |win32con.DS_SYSMODAL
h=win32gui.CreateDialogIndirect(
    win32api.GetModuleHandle(None),
    [['One ugly dialog box !',(100,100,200,100),style,0],
     ['Button','Create', win32con.IDOK, (10,10,30,20),win32con.WS_VISIBLE|win32con.WS_TABSTOP|win32con.BS_HOLLOW|win32con.BS_DEFPUSHBUTTON],
     ['Button','Never mind', win32con.IDCANCEL, (45,10,50,20),win32con.WS_VISIBLE|win32con.WS_TABSTOP|win32con.BS_HOLLOW],
     ['Static','Desktop name:',71,(10,40,70,10),win32con.WS_VISIBLE],
     ['Edit','',72,(75,40,90,10),win32con.WS_VISIBLE]],
    parent_hwnd, msgs)

win32gui.EnableWindow(h,True)
hcontrol = win32gui.GetDlgItem(h,72)
win32gui.EnableWindow(hcontrol,True)
win32gui.SetFocus(hcontrol)
win32gui.PumpMessages()
person zvone    schedule 03.04.2016
comment
Я не знаю, почему этот работает. В чем разница? Любое объяснение приветствуется. Не стесняйтесь редактировать мой ответ с объяснением;) - person zvone; 03.04.2016
comment
К сожалению, диалог - это не то, что я хочу. Моя реализация tkinter работает так, как и ожидалось (даже пропускает отключенные элементы управления), мне просто не нравится весь багаж (файлы), связанный с tkinter, и, возможно, в конечном итоге я захочу перейти на C++. - person mjpsr11; 03.04.2016
comment
Вы можете выйти (завершить) эту программу, которую вы принесли сюда? Я не могу! Мне нужно убить процесс (pyton.exe) из диспетчера задач. Господи, мужик! - person Apostolos; 10.08.2018

Есть два ответа, короткий и длинный.

Короткий ответ: просто установите клавиатуру v0.6.5.

Длинный ответ: найдите короткий код клавиатуры, а затем установите его.

person Charles Merriam    schedule 31.03.2016
comment
Хотя эта ссылка может ответить на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если связанная страница изменится. - person Tadhg McDonald-Jensen; 01.04.2016
comment
Если ссылки PyPi меняются, у вас гораздо больше проблем. - person Charles Merriam; 02.04.2016
comment
Хотя эта ссылка может дать ответ на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы только по ссылке могут быть недействительными, если использование примера кода со связанной страницы вызывает AttributeError: 'NoneType' object has no attribute 'read_event' - person Tadhg McDonald-Jensen; 02.04.2016
comment
Хотя все возможные события клавиатуры и мыши можно обрабатывать вручную, вопрос заключается в том, как позволить ОС делать то, что она обычно делает, а не переопределять все заново. - person zvone; 03.04.2016