KAction and KAccel tutorial
First of all: don't use KAccel. You are meant to use KAction whenever possible,
since it provides better configuration abilities.
There are plans to remove direct configuration of KAccel - so simply use
KAction, it does the rest.
You also should not hardcode keys. For example don't use something like
void MyWidget::keyPressedEvent(QKeyEvent* e)
{
if (e->key() == Qt::Key_Up) {
doSomething();
}
}
or the same using KAccel.This is not the way to go, as you should allow the user to change the keys for every event.
Instead you can simply use KAction for keys. KAction is not only meant for menu or toolbar items but for key-only actions, too. Simply use
(void)new KAction(i18n("Move Up"), Qt::Key_Up, this, SLOT(doSomething()),
actionCollection(), "move_up");
to achieve the above using KAction.
Additional KActionCollection objects
There are situations, especially in games, where this is not the ideal thing to do, since you need to have access to KMainWindow::actionCollection() which you often don't have. If you want to avoid ugly hacks you can just create your own KActionCollection object:
mActionCollection = new KActionCollection(this);
(void)new KAction(i18n("Move Up"), Qt::Key_Up, this, SLOT(doSomething()),
mActionCollection, "move_up");
As a side effect you get another section in KKeyDialog::configure() which helps
to logically separate your actions from others.
Different KActions for a single slot
A few things are left that often come up in games. E.g. think about several different keys which do slightly the same. For example in a poker game you can exchange every card - 5 functions that do exactly the same but for a different card. You can either create 5 slots or you can give an integer parameter to one slot through the use of QSignalMapper. This is especially *very* useful when you want to define a dynamic number of actions (think of unit groups in a strategy game for example). Here is the code:QSignalMapper *cardMapper = new QSignalMapper( this ); connect( cardMapper, SIGNAL( mapped( int ) ), this, SLOT( exchangeCard( int ) ) ); exchangeCardAction1 = new KAction( .., cardMapper, SLOT( map() ), actionCollection() ); exchangeCardAction2 = new KAction( .., cardMapper, SLOT( map() ), actionCollection() ); exchangeCardAction3 = new KAction( .., cardMapper, SLOT( map() ), actionCollection() ); exchangeCardAction4 = new KAction( .., cardMapper, SLOT( map() ), actionCollection() ); exchangeCardAction5 = new KAction( .., cardMapper, SLOT( map() ), actionCollection() ); cardMapper->setMapping( exchangeCardAction1, 1 ); cardMapper->setMapping( exchangeCardAction2, 2 ); cardMapper->setMapping( exchangeCardAction3, 3 ); cardMapper->setMapping( exchangeCardAction4, 4 ); cardMapper->setMapping( exchangeCardAction5, 5 );
key[Release|Press]Event and KAction
In another scenario you don't want to rely on the usual keyrepeat rate but really need to use keyPressEvent() and keyReleaseEvent(). This is usually the case e.g. for a 2d scroller where the player moves forward while an arrow key is pressed and stops once its released. So you really don't want to use slots. But you can still use KAction for this:
mAction = new KAction(i18n("Move Left"), Qt::Key_Left, 0, 0,
actionCollection(), "move_left");
[...]
and in
MyWidget::keyPressedEvent(QKeyEvent* event):
KKey key(event);
if (mAction->shortcut().contains(key)) {
doSomething();
}
You should use KShortcut::contains() because a KShortcut can have two, not only
one, key sequences assigned. As you can see from the example above, you don't need to provide a slot/receiver for a KAction object. Simply passing 0 as receiver/slot disables slots.
Please note that this does not work for KDE 3.0.x but only for KDE >= 3.1!
key[Press|Release]Event() do not get called in 3.0.x even if there is no slot
assigned to the action.
KKeyDialog and keys without modifier
In KDE versions < 3.1 there is a bug in KKeyDialog which lets you not assign letters without modifier key as a shortcut. This is fixed in KDE >= 3.1 - if you want the user to assign normal keys in previous versions you just have to avoid KKeyDialog::configure(). Use:
KKeyDialog dlg(true); dlg.insert(actionCollection()); dlg.configure(true);instead of
KKeyDialog::configure(actionCollection());
Last update: 2008-01-11
Thanks to Leif Huhn for the update.
The KDE Education Project