Я разрабатываю графический интерфейс, который имеет холст и кучу элементов управления и дерьмо, окружающее его. Я хочу дать обработчику событий холста возможность обрабатывать такие события, как нажатия клавиш и тому подобное, когда он не имеет фокуса. Я хочу, чтобы остальные продолжали работать в обычном режиме.
В основном то, что я хочу настроить, это сообщить фрейму: «Любое событие, которое вы получаете, но которое вы сами не обрабатываете, перенаправляете его на тот холст, который в данный момент активен». Мне нужен самый быстрый и безболезненный способ сделать это... желательно всего пару строк кода.
Проблема возникает в вещах, которые обрабатывают нажатия клавиш для изменения своего состояния. Например, если вы удерживаете нажатой клавишу Ctrl, мы перестаем привязываться к координатам сетки, но есть условия, при которых мы не получаем уведомления о нажатии и поэтому не можем обновить курсор, пока пользователь не переместит мышь (в этот момент мы проверяем событие для ключа). Мы получаем прессу, только если фокус находится в контроле. Мы сталкивались с этой проблемой раньше и просто обходили ее, но теперь есть пара условий, которые просто невозможно обойти без этого механизма пересылки.
Спасибо.
=======================================================
Ответ заключается в том, что на самом деле нет простого способа сделать это. Вы не можете просто отправить что-либо, что не обработано, в дочерний виджет, потому что, если он его не обработает, вы получите его снова... и затем снова отправите его вниз....и т.д... переполнение стека. Я на самом деле был взволнован, когда мне наконец удалось вызвать это...
Вы также не можете просто переопределить ProcessEvent во фрейме приложения. Вы должны переопределить его в производном объекте App, который инкапсулирует программу. Причина этого в том, что вы потратите много дополнительного времени, пытаясь зафиксировать события, которые никогда не достигают этой точки... например, нажатие клавиши (то, которое я специально хотел в это время). Однако функция wxApp::ProcessEvent всегда вызывается, когда событие не обрабатывается.
Вы не можете просто вызвать ProcessEvent для своей цели (даже временно забыв первый абзац), потому что он не вызывает обработчики, которые вы на него нажали. Если обработчик для события был добавлен к цели с помощью PushEventHandler, он не будет достигнут через target->ProcessEvent(event)
, вместо этого вам нужно активировать сами обработчики с помощью target->GetHandler()->ProcessEvent(event)
.
Однако, опять же, вы не можете даже этого сделать, потому что вы получите все, что не было обработано напрямую, и отправите это обратно... получите обратно... отправьте обратно...
Ответ заключается в том, чтобы написать копию ProcessEvent в целевом обработчике, который не использует TryParent, в дополнение к переопределению wxApp::ProcessEvent. В итоге я просто оставил указатель на обработчик, который имеет дело с событиями, которые я хочу переслать, а затем, в конце концов (за кучей абстракций), вызвал this->GetEventHashTable().HandleEvent(event,this)
, где «это» является обработчиком, который нужно активировать. Это ключевая строка в wxEvtHandler::ProcessEvent, которая фактически захватывает функцию из вашей таблицы и активирует ее; он пропускает валидатор, еще какую-то хрень и не использует TryParent.
Вот так я победил WX и сделал невозможное.