Способ быстрой настройки пересылки событий в wxWidgets?

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

В основном то, что я хочу настроить, это сообщить фрейму: «Любое событие, которое вы получаете, но которое вы сами не обрабатываете, перенаправляете его на тот холст, который в данный момент активен». Мне нужен самый быстрый и безболезненный способ сделать это... желательно всего пару строк кода.

Проблема возникает в вещах, которые обрабатывают нажатия клавиш для изменения своего состояния. Например, если вы удерживаете нажатой клавишу 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 и сделал невозможное.


person Edward Strange    schedule 29.07.2010    source источник


Ответы (1)


Вы можете использовать метод ProcessEvent.

В обработчиках событий, которые вы хотите переслать, добавьте

/* Let the canvas process this event too */ 
canvas->ProcessEvent(aEvent);

где «canvas» — это статический глобальный указатель на ваш холст, а «aEvent» — это объект события, полученный вашим обработчиком.

Таким образом, вы даже можете моделировать события! Это то, что я использую для своей системы регрессионного тестирования графического интерфейса...

person Rui Curado    schedule 29.07.2010
comment
Да, работаю над этим, чтобы увидеть, сработает ли это, за исключением того, что я проверяю, обработал ли его мой родитель первым: if(!wxAuiParentFrame::ProcessEvent(....)).... К сожалению, VS2010 полностью сошел с ума и поэтому мне пришлось все поцарапать, перепроверить и начать заново .... до сих пор был отличный день :P - person Edward Strange; 30.07.2010
comment
Это НЕ работает для меня, и это действительно должно. Я создаю подкласс wxScrolledWindow для выполнения своей работы, и все работает нормально при переходе через обычные каналы, но когда я вызываю ProcessEvent из фрейма, он смотрит только на обработчик wxScrolledWindow... он просто пропускает все обработчики, которые я нажал на стек обработчиков! Я подумал, может быть, это запутанная система типов wx, но я переделал ее, создав собственную функцию process_event в самом производном классе, который вызывает ProcessEvent. Меня это начинает бесить :p - person Edward Strange; 30.07.2010
comment
Еще более странно... похоже, что это не работает так, как задокументировано. ProcessEvent вызывается в моем фрейме, не достигая сначала моего окна. Затем, когда фокус находится в окне, я пытаюсь нацелить событие, которое обрабатывается правильно, когда фокус находится не в этом окне, он отправляется в базовый класс и не попадает в мои обработчики. - person Edward Strange; 30.07.2010
comment
Принимая это как начало ответа. Полная информация будет в вопросе редактирования. - person Edward Strange; 02.08.2010