Т.Л., д-р
Хорошо, так что я сделал немного рыть. Причина, по которой ключ получает «застревание» в событии matplotlib, заключается в том, что бэкенд matplotlib использует события нажатия клавиш и клавиш, чтобы выяснить, какая клавиша нажата при нажатии мыши. Когда клавиша нажата, ее запоминают до тех пор, пока она не будет отпущена, поэтому, если пользователь делает key press --> mouse click --> key release
, они будут нажаты и запоминаются и передаются обработчику событий щелчка мыши.
Поэтому, когда я запускаю новое окно и фокусирую его на событии клика, последующее событие релиза ключа «потеряно»: первый кадр никогда не получает его, поэтому бэкенд не сбрасывает его кешированное нажатие клавиши и сообщает устаревшее значение для всех последующих щелчков мыши до тех пор, пока не будет создано новое событие нажатия клавиши.
Там не кажется хорошим решением для конкретной задачи, в которой главное окно теряет фокус между нажатием клавиши и отпустить событие ...
Остальная часть объяснения
Этот ключ кеширование можно найти в backend_bases.py
, который по моей системе Ubuntu находится в /usr/local/lib/python2.7/dist-packages/matplotlib/backends
. Событие нажатия клавиши спрятало текущий ключ в self._key
и сбрасывает его до None
, когда ключ отпущен.
Трассировка стека от события подборщика моего первого кадра заключается в следующем:
File "test.py", line 57, in <module>
app.MainLoop()
File "/usr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode/wx/_core.py", line 8010, in MainLoop
wx.PyApp.MainLoop(self)
File "/usr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode/wx/_core.py", line 7306, in MainLoop
return _core_.PyApp_MainLoop(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_wx.py", line 1069, in _onLeftButtonDown
FigureCanvasBase.button_press_event(self, x, y, 1, guiEvent=evt)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/backend_bases.py", line 1910, in button_press_event
self.callbacks.process(s, mouseevent)
<snip>
File "/usr/local/lib/python2.7/dist-packages/matplotlib/backend_bases.py", line 1787, in pick
self.figure.pick(mouseevent)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/artist.py", line 450, in pick
a.pick(mouseevent)
<snip>
File "/usr/local/lib/python2.7/dist-packages/matplotlib/artist.py", line 436, in pick
self.figure.canvas.pick_event(mouseevent, self, **prop)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/backend_bases.py", line 1874, in pick_event
self.callbacks.process(s, event)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/cbook.py", line 563, in process
proxy(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/cbook.py", line 430, in __call__
return mtd(*args, **kwargs)
File "test.py", line 22, in _OnGraphPickEvent
for line in traceback.format_stack():
Спускаясь уровень в классе FigureCanvasWx
функции и _onKeyUp()
привязанные к ключевым пресс-конференции WxWidgets. Они вызывают базовый класс FigureCanvasBase
соответствующих функций обработчика событий.Как сказано, это FigureCanvasBase
, который затем кэширует информацию о нажатии клавиши, чтобы она могла передать текущую клавишу, нажатую на события мыши, которые в конечном итоге достигают события выбора.
Я добавил несколько отладочных отпечатков в вышеуказанные классы. Дает следующее ...
Тест 1: показан первый кадр. Я нажимаю на график, но не на точку, потому что я не хочу запускать событие выбора, которое показывает новый кадр.
FigureCanvasWx:onLeftButtonDown: Ctrl down is "False"
FigureCanvasBase:button_press_event: KEY IS None
Artist:Pick:MPL MouseEvent: xy=(475,156) xydata=(2.88911290323,1.34375) button=1 dblclick=False inaxes=Axes(0.125,0.1;0.775x0.8) None
Хорошо, что работает должным образом. wxPython и matplot lib согласны с нажатием клавиши управления.
Test 2: Теперь нажмите клавишу управления и нажмите на графике, но не на точке, просто пустое место, еще раз, чтобы увидеть эффект без стрельбы события подборщика, в котором новый кадр показано на рисунке.
FigureCanvasBase:key_press_event: SETTING KEY TO control
FigureCanvasWx:onLeftButtonDown: Ctrl down is "True"
FigureCanvasBase:button_press_event: KEY IS control
Artist:Pick:MPL MouseEvent: xy=(440,144) xydata=(2.67741935484,1.25) button=1 dblclick=False inaxes=Axes(0.125,0.1;0.775x0.8) control
FigureCanvasBase:key_release_event: RESETTING KEY #<<!! THE IMPORTANT BIT
При нажатии клавиши управления Направьте FigureCanvasBase
кэширует нажатие клавиши. Затем, когда событие mouse из wxPython завернуто в событие matplotlib, это кешированное значение ключа добавляется к событию matplotlib. На данный момент matplotlib и wxpython все еще согласны.
После моего нажатия я отпускаю управляющий ключ, а FigureCanvasBase
правильно сбрасывает кеш ключа. Поэтому, когда я нажимаю снова, не удерживая клавишу управления, событие matplotlib правильно сообщает, что нажатие клавиши не выполняется.
Тест 3: * Теперь удерживайте клавишу управления вниз и нажмите на фактическую точку на моем графике, который выстреливает мой пикап событие, в котором создается новое окно, отображаются и данный фокус:
FigureCanvasBase:key_press_event: SETTING KEY TO control
FigureCanvasWx:onLeftButtonDown: Ctrl down is "True"
FigureCanvasBase:button_press_event: KEY IS control
Artist:Pick:MPL MouseEvent: xy=(494,238) xydata=(3.00403225806,1.984375) button=1 dblclick=False inaxes=Axes(0.125,0.1;0.775x0.8) control
FigureCanvasBase:pick_event: CREATED PICK EVENT <matplotlib.backend_bases.PickEvent object at 0xaf631ec> control
control True
Этот путь в порядке ... matplotlib и wxpython все еще согласны .... но подождите ...
О нет ... Я отключаю управляющий ключ, но в первом кадре больше нет фокуса ... нет событие выпуска ключа
Итак, теперь, когда я нажимаю любую точку на графике, пустое пространство события, я буду видеть, что клавиша управления нажата!
FigureCanvasWx:onLeftButtonDown: Ctrl down is "False" ##<< !!!!
FigureCanvasBase:button_press_event: KEY IS control ##<< !!!!
ARTIST PICK MPL MouseEvent: xy=(475,475) xydata=(None,None) button=1 dblclick=False inaxes=None control
Единственный способ очистить это сделать первый фокус кадра и намеренно нажать клавишу, так что событие сброса может очистить кэш.
Интересно, что второй кадр, как представляется, не получает событие релиза, если я не намеренно нажимаю на него, прежде чем отпускать управляющий ключ, который помешает мне отправить это событие в первое окно и обойти его таким образом.
Итак ... похоже, что ключевая схема кэширования была проблемой в этом конкретном сценарии. Работа вокруг, кажется, единственный способ справиться с этим. Если бы мы могли заставить wxPython перечитать состояние клавиатуры вручную, мы могли бы исправить это, но в большинстве случаев, даже для функции wx.GetKeyState()
, она будет сообщать только о том, не были ли клавиши управления, а не какой-либо ключ, чего хочет matplotlib.
попробуйте вызвать event.Skip() в конце обработчика. – Igor
Увы: AttributeError: объект 'PickEvent' не имеет атрибута 'Skip' Если я делаю event.guiEvent.Skip(), это не помогает :( Спасибо в любом случае :) – Jimbo
Я написал запись.Skip() и не event.guiEvent.Skip(), правильно? ;-) – Igor