PDA

View Full Version : keyPressEvent combined with QMouseEvent to achieve meaningful key binding



Tepi
15th October 2009, 06:59
Hello everyone,

I'll start by explaining a little bit of background situation... so here's the deal.

I have a main window which shows multiple custom widgets, these are called services in my program. These services consists of multiple widgets, such as QSliders, QPushButtons etc. whatever widgets the services might want to show.

Here comes the problem:

I have a situation where some services might need to have keys binded to some specific operations, such as controlling a radio-controlled car (this is a real RC car). So I want to bind keys "w", "a", "s" and "d" for controls of the car. There's also some widgets (somekind of a meters or something similar) to display the throttle and steering information. These widgets should also react to the binded keys.

Problematic part here is that I might have multiple services which all might need keys, also same keys, binded to different things. So the determination of which service should get the keyPressEvents at some specific time is needed.

I have thought of using mouse to determine to which service keyPressEvents should go. It should work like so: if I have a mouse cursor over some service (or maybe if I have clicked mouse over the service) the keyPressEvents should go to that specific service. What do you think about this solution? Any other suggestions?

How can I implement this feature? I have tried of using setMouseTracking on those services and when the mouse is over some service it shows that services name as a tooltip. So somehow it is able to know the specific services which has the mouse over. Is there something like hasMouseOver() function on QWidget or QObject or some other class... Any ideas how to get keyEvents directed as I described above with the help of mouse?

And for the key bindings, should I reimplement the keyPressEvent or can I use QActions with some shortcut keys? Which one would you recommend?

Any help/ideas is/are greately appreciated.

Greetings,
-Tepi

spirit
15th October 2009, 07:25
maybe QApplication::widgetAt function will help you.

Tepi
15th October 2009, 07:57
Thanks Spirit for your reply. That seems useful...

...but I just got a message that we need to change specifications a bit. So with the new specs we don't need to know which service has the mouse on. Now I need to implement the key binding simply by pressing some button "Bind keys" or something like that. This is because we might need to control the RC Car and use some other services at the same time. And with the old specs that wouldn't be possible because the key bindings would be gone if we move the mouse over some other service.

If you got some suggestions feel free to post them here...

Tepi
15th October 2009, 08:15
What do you guys think should I reimplement the keyPressEvent or is it easier to use QActions with shortcuts it my case. I mean with my new specifications...

I thought of first trying with QActions with shortcuts... feels easier to implement some new QActions when I press the "Bind keys" button and after pressing "Unbind keys" just remove those actions.

What do you think?

spirit
15th October 2009, 08:36
int this case I would use QShortcut, for example


...
A::A(QWidget *parent)
: QFrame(parent)
{
setFrameStyle(QFrame::Panel | QFrame::Raised);
setFocusPolicy(Qt::StrongFocus);

new QShortcut(QKeySequence(tr("A")), this, SLOT(action()), 0, Qt::WidgetShortcut);
}

void A::action()
{
QMessageBox::information(this, tr("information"), tr("A::action"));
}

B::B(QWidget *parent)
: QFrame(parent)
{
setFrameStyle(QFrame::Panel | QFrame::Raised);
setFocusPolicy(Qt::StrongFocus);

new QShortcut(QKeySequence(tr("A")), this, SLOT(action()), 0, Qt::WidgetShortcut);
}

void B::action()
{
QMessageBox::information(this, tr("information"), tr("B::action"));
}

Test::Test(QWidget *parent)
: QDialog(parent)
{
QVBoxLayout *vbl = new QVBoxLayout(this);
vbl->addWidget(new A());
vbl->addWidget(new B());
}
...

classes A and B can be your services.

Tepi
15th October 2009, 09:31
That would have been perfect solution... with the old specs ;)

Maybe I can use something similar with the new specs, lets see...

Tepi
16th October 2009, 09:30
I'm little bit confused...

The shortcut solution seems like good solution for me but there's some strange things going on... I tried it with my service which haves two QSlider widgets and when I connected the key sequence to the slider widgets SLOT(setFocus()) it worked out alright.



new QShortcut(QKeySequence(QObject::tr("w")), component->getComponent(), SLOT(setFocus()), 0, Qt::WindowShortcut);


In the code, "component" is instance of my own class GUIComponent (this represents gui components in services. GUIComponent class inherits QWidget). getComponent method returns a pointer to the specific widget, in this case QSlider. This works as it should.

But when I replace the SLOT(setFocus()) part with my own slot which is implemented in GUIComponent class, it won't work...



new QShortcut(QKeySequence(QObject::tr("w")), component, SLOT(adjustValue()), 0, Qt::WindowShortcut);


With this code the slots code is never called. What's the problem? I thought this should be quite straight forward thing to do...

spirit
16th October 2009, 14:28
try to replace Qt::WindowShortcut with Qt::WidgetShortcut.

Tepi
16th October 2009, 14:44
That doesn't help. And the windowShortcut is the needed context for me, i think...

Because I want the shortcut to be available whenever the focus is on my main window, not just when the focus is on the specific service.

Little bit frustrating because as I said in my last post it seems so straight forward :confused: