Intercepting raw key events is not currently supported, unless you want to work directly with the toolkit widget via foo.proxy.widget
(on the 0.7+ series; the 0.6 series is no longer supported). You can, however, define a MenuBar with Actions which support accelerator keys triggered by custom action names such as "Cut\tCtrl+C" and "Paste\tCtrl+V".
How to get key events when using enaml?
Question
I've been using enaml (0.6.8 which is what is available with Canopy for now) and have successfully created some very useful utility applications. I would like, however, to intercept keyboard events to enable some quick keyboard shortcuts rather than repetitive button-clicking in the UI.
How do I approach this? I understand that this will be toolkit (qt4) specific, but cannot really figure out where to begin. I've read some on event filters in qt, which seem like what I might want, but I do not understand the mechanisms for relating QApplication, etc. to enaml
Solution
OTHER TIPS
I created a rather crude way of doing this. Make a file named key_event.py
with the following:
# -*- 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
In your enaml file import the KeyEvent
and use like this:
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...
Probably not the best way to do it but it worked fine for my needs.