我一直在使用 enaml(目前 Canopy 提供的 0.6.8)并成功创建了一些非常有用的实用程序应用程序。但是,我想拦截键盘事件以启用一些快速键盘快捷键,而不是在 UI 中重复单击按钮。
我该如何处理?我知道这将是特定于工具包(qt4)的,但无法真正弄清楚从哪里开始。我在 qt 中阅读了一些关于事件过滤器的内容,这似乎是我想要的,但我不明白将 QApplication 等与 enaml 相关联的机制
当前不支持拦截原始键事件,除非您想直接使用工具包小部件foo.proxy.widget
(在 0.7+ 系列上;不再支持 0.6 系列)。但是,您可以使用支持由自定义操作名称(例如“Cut\tCtrl+C”和“Paste\tCtrl+V”)触发的加速键的操作定义菜单栏。
我创造了一种相当粗糙的方式来做到这一点。创建一个文件,命名key_event.py
如下:
# -*- coding: utf-8 -*-
'''
Created on Jul 20, 2015
@author: jrm
'''
from atom.api import (Callable,Event, Value, Unicode, Bool, Instance,Typed, ForwardTyped, observe)
from enaml.core.declarative import d_
from enaml.widgets.control import Control, ProxyControl
from enaml.qt.qt_control import QtControl
from enaml.qt import QtCore
class ProxyKeyEvent(ProxyControl):
declaration = ForwardTyped(lambda: KeyEvent)
def set_enabled(self, enabled):
raise NotImplementedError
class KeyEvent(Control):
proxy = Typed(ProxyKeyEvent)
key_code = d_(Value())
key = d_(Unicode())
enabled = d_(Bool(True))
repeats = d_(Bool(True))
pressed = d_(Event(),writable=False)
released = d_(Event(),writable=False)
@observe('enabled')
def _update_proxy(self, change):
""" An observer which sends state change to the proxy.
"""
super(KeyEvent, self)._update_proxy(change)
class QtKeyEvent(QtControl, ProxyKeyEvent):
_keyPressEvent = Callable() # Refs to original functions
_keyReleaseEvent = Callable() # Refs to original functions
widget = Instance(QtCore.QObject)
def create_widget(self):
self.widget = self.parent_widget()
def init_widget(self):
super(QtKeyEvent, self).init_widget()
d = self.declaration
widget = self.parent_widget()
self._keyPressEvent = widget.keyPressEvent
self._keyReleaseEvent = widget.keyPressEvent
self.set_enabled(d.enabled)
def set_enabled(self, enabled):
widget = self.parent_widget()
if enabled:
widget.keyPressEvent = lambda event:self.on_key_press(event)
widget.keyReleaseEvent = lambda event:self.on_key_release(event)
else:
# Restore original
widget.keyPressEvent = self._keyPressEvent
widget.keyReleaseEvent = self._keyReleaseEvent
def on_key_press(self,event):
try:
if (self.declaration.key_code and event.key()==self.declaration.key_code) or \
(self.declaration.key and self.declaration.key in event.text()):
if not self.declaration.repeats and event.isAutoRepeat():
return
self.declaration.pressed(event)
finally:
self._keyPressEvent(event)
def on_key_release(self,event):
try:
if (self.declaration.key_code and event.key()==self.declaration.key_code) or \
(self.declaration.key and self.declaration.key in event.text()):
if not self.declaration.repeats and event.isAutoRepeat():
return
self.declaration.released(event)
finally:
self._keyReleaseEvent(event)
def key_event_factory():
return QtKeyEvent
# Inject the factory
from enaml.qt.qt_factories import QT_FACTORIES
QT_FACTORIES['KeyEvent'] = key_event_factory
在您的 enaml 文件中导入KeyEvent
并使用如下:
WidgetToWatchKeys:
KeyEvent:
key_code = QtCore.Qt.Key.Key_Up
pressed :: model.move_up()
KeyEvent:
key_code = QtCore.Qt.Key.Key_Left
pressed :: model.move_left()
KeyEvent:
key = 'x'
pressed :: model.fire()
#: etc...
可能不是最好的方法,但它可以很好地满足我的需求。