I am learning to process keypress and keyrelease events in Qt (C++). I have a class Keyboard with which I want to process all of these events. It inherits QObject. It doesn't need to process any mouse events. I am trying to figure out how I can direct all of the keyboard input when my application is open to that class.
I've tried adding it as a widget in a layout of my MainWindow class and hiding it (the widget, not the layout). Currently, that is not responding.
I've also tried this in my MainWindow class:
void MainWindow::keyPressEvent(QKeyEvent *event)
{
keys->keyPressEvent(event);
//Keys is a Keyboard object with this public method:
//void keyPressEvent(QKeyEvent *event);
}
But that's not working either. In my Keyboard::Keyboard() constructor, I have:
this->setFocusPolicy(Qt::StrongFocus);
I'm not sure if there's anything else I need to do to make sure the keyboard input gets there.
If someone knows a way to send all keyboard events to this class for my Qt application, it would be very helpful!
Thanks,
John
For anyone who wants to know, I found the answer to my question.
In the constructor for the class that is handling my keyboard events, I added this line:
QWidget::grabKeyboard();
and now all the keyboard input when that application is active goes straight to that widget.
You can check the reference for more information:
QWidget::grabKeyboard.
Note: nothing else (i.e., no other widgets) will get keyboard input until you call QWidget::releaseKeyboard().
Related
I have a MainWindow class in Qt, in which several checkable QGroupBox widgets are placed.
What I want to do is, to trigger a general onClick(bool checked) slot whenever one (any) of the QGroupBox objects are clicked, identify the sender and trigger some code.
I need to capture the objects' "clicked" signal in order to prevent a disabling action it performs on its children when the control is clicked.
This is the signal I'm trying to handle:
class Q_WIDGETS_EXPORT QGroupBox : public QWidget
{
...
Q_SIGNALS:
void clicked(bool checked = false);
...
};
I tried adding a custom slot like this and tried connecting it with the signal above but since QGroupBox at its own is not an object or pointer, the operation fails.
void MainWindow::onClick(bool clicked)
{
qDebug()<<"Custom slot triggered";
}
Long story short, I need to handle a control type's default behavior within my MainWindow class.
Thanks for any ideas in advance.
I need to capture the objects' "clicked" signal in order to prevent a disabling action it performs on its children when the control is clicked.
Perhaps, but I'm smelling an XY Problem here. You can certainly prevent emission of signals by invoking blockSignals() on the widget. But that's a hack - it will also prevent Qt's internals from acting on the object's destroyed() signal, and you might subtly break other users of the object's signals.
Instead, one could make the UI stateful and have the controller implement the stateful aspect of the button's interaction with the rest of the application. Currently, the button's clicked() signal is connected directly to other users. Instead, connect the button to the controller, and have the controller disable the children only when it's appropriate to do so. One could use the QStateMachine to make this stateful behavior explicit in terms of states.
#Kuba Ober, maybe you're right, I could not state my problem and the facts around it seperately and clearly. Thank you for pointing that out.
After checking out the QGroupBox class' source, I discovered that a "toggle" signal is emitted after every other operation in a "clicked" event.
http://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/widgets/qgroupbox.cpp
void QGroupBox::setChecked(bool b)
{
Q_D(QGroupBox);
if (d->checkable && b != d->checked) {
update();
d->checked = b;
d->_q_setChildrenEnabled(b);
#ifndef QT_NO_ACCESSIBILITY
QAccessible::State st;
st.checked = true;
QAccessibleStateChangeEvent e(this, st);
QAccessible::updateAccessibility(&e);
#endif
emit toggled(b);
}
}
By combining this information with that of #rbaleksandar 's suggestion, I managed to obtain a solution.
I iterated through the controls of my MainWindow class and connected every QGroupBox's "toggle" signal with a common "MainWindow::onToggle" slot in which I could handle the post-event operations I desire.
As for my previous approach, I could've created a class which inherits QGroupBox and override any methods I wish to. But that would be overkill compared to my current solution. The fix I've came up with did the trick perfectly.
Thanks everyone for their insight and help.
I have a complex widget on the screen which is visible. By pushing a button a dialog appears but parts of the original widget is still visible. When closing the dialog I would like to refresh some data of my particular widget ... but this widget does not know anything about that dialog. Is there any event I can check for this purpose ? Or any other way to get to know when the dialogs closed ?
First I used
virtual void QWidget::showEvent( QShowEvent* event );
but it is not called when the parts of the widget is already visible.
EDIT
I'm sorry but I wasn't precise enough. When I wrote complex, I meant that I have a main window, which has a child widget which also has child widget and so on (for about file level). That lowest level child widget initiates the opening of the dialog. The other widget which needs the closing event of this dialog is also an embedded widget but somewhere else in the application. When I wrote sending the signal through many classes I meant this. In this case if want to notify my final widget I have to connect the closing signal from my source widget to several intermediate widgets which does not even interested in that signal. I also didn't want to (and can't) connect these signal/slot in the main window because of the mentioned structure. In this is there any advice ?
send the signal through many objects just for this purpose
There's no such thing as sending a signal "through" objects unless you insist on manually threading it through a bunch of them. So this doesn't make much sense unless you explain why you want to "thread" the signal through many objects ("threading" as in a string through a needle, not as in a processing thread).
A signal-slot connection has two endpoints. All you need is:
A signal at the dialog.
A slot at the supercomplex widget.
A connection set up outside of both of them. To make life simple, both the widget and the dialog could be instantiated in main(), and a connection set up before anything even appears on the screen.
The dialog signal you're looking for is simply QDialog::finished, if you have a properly designed dialog. Otherwise, use an EventSignaler of some sort to convert a QEvent::close to a signal.
The slot in the supercomplex widget should be e.g.:
Q_SLOT void refreshSomething();
Its signature/name shouldn't refer to the fact that some dialog was closed: that's coupling the API too much to the external detail of some dialog being there. The slot should get the dialog to update/refresh what you need. The reasons for invoking it are irrelevant to the widget.
Inside the widget, the slot's implementation should most likely simply call update() on one or more subwidgets, perhaps with a relevant region - if you wish to, you can have the region as an optional slot parameter.
See this question about how to forward signals or slots inside of a complex composite class that contains many objects. It's supposed to be very simple; if it's not you'll have to edit the question to indicate why it's complex for you.
At the simplest, with the most decoupled code - where the dialog knows nothing about the widget, and vice versa - as it should be, you can have:
class Dialog : public QDialog { ... };
class Widget : public QMainWindow {
Q_OBJECT
Q_SIGNAL void showDialog();
Q_SLOT void refreshSomething();
...
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
...
Widget widget;
Dialog dialog;
QObject::connect(&widget, &Widget::showDialog, &dialog, &QWidget::show);
QObject::connect(&dialog, &QDialog::finished, &widget, &Widget::refreshSomething);
widget.show();
return app.exec();
}
I'm making a simple game with Qt and I'd like to pause the game when the user switches to a different window (this could be by minimizing it or by accidentally clicking on a window beside it, etc). My game is wrapped in a QMainWindow, so I'd like to be able to detect when that loses focus.
I've tried a few different methods for this, but I haven't been successful. I first tried overloading QMainWindow's focusOutEvent, but this method was only called when I first gave the window focus with setFocus. I also tried to overload the window's event(QEvent *) method to check for QEvent::ApplicationActive and QEvent::ApplicationDeactivate.
I would post the code for my QMainWindow but there isn't much to show, I literally just tried to implement those two methods but neither were called. I did nothing else to set up those methods (maybe I'm missing a step?).
Does anyone know a good way to determine if your QMainWindow has "lost focus"?
I had a similar need once, and resolved it by overloading event(QEvent*) method of my QMainWindow :
bool MyMainWindow::event(QEvent * e)
{
switch(e->type())
{
// ...
case QEvent::WindowActivate :
// gained focus
break ;
case QEvent::WindowDeactivate :
// lost focus
break ;
// ...
} ;
return QMainWindow::event(e) ;
}
From the documentation -
A widget normally must setFocusPolicy() to something other than
Qt::NoFocus in order to receive focus events. (Note that the
application programmer can call setFocus() on any widget, even those
that do not normally accept focus.)
From this part of the documentation, about focusPolicy-
This property holds the way the widget accepts keyboard focus.
The policy is Qt::TabFocus if the widget accepts keyboard focus by
tabbing, Qt::ClickFocus if the widget accepts focus by clicking,
Qt::StrongFocus if it accepts both, and Qt::NoFocus (the default) if
it does not accept focus at all.
You must enable keyboard focus for a widget if it processes keyboard
events. This is normally done from the widget's constructor. For
instance, the QLineEdit constructor calls
setFocusPolicy(Qt::StrongFocus).
So set your focus policies accordingly, I guess then you will receive appropriate focus events.
Try QWidget::isActiveWindow() .
I'm trying to change the default behavior of context menus: Instead of opening on the release event of the right mouse button, I want it to open on the press event, and it's actions to be triggered on the release event). On one widget I could overload the mousePressEvent() and fire a custom contextmenu event, but I want it to be global to all the context menus of my program...
Any ideas?
Thanks.
I was trying to implement a widget base on top of QWidget with a custom way to handle context menu to suit your needs when I realize that using ActionsContextMenu policy with actions directly own by the widget does exactly the behavior you are expecting. (Qt 4.6.2 & 4.7 on linux, didn't try on windows yet but I don't know why the behavior should be different).
Is that a policy you can use ? If you don't really need external menus, I'll suggest to go with this solution.
Otherwise you will have to create your own widget base with a custom QMenu member. You should use the Qt::PreventContextMenu policy to guarantee the right click to end in the void mousePressEvent(QMouseEvent *event) of your widget. In this event handler make sure to show your menu. In your menu re-implement the void mouseReleaseEvent( QMouseEvent *event) if it don't trigger the current action do it your-self with the mouse position (in the event) and the QAction* actionAt( const QPoint & pt) const. But be careful the void mouseReleaseEvent( QMouseEvent *event) of the QMenu is already re-implemented from QWidget and may do some stuff you want to preserve !
EDIT
It's kind of sad but this behavior seems to be different by design on windows the void QMenu::mouseReleaseEvent(QMouseEvent *e) does the following:
Extracted form qmenu.cpp, Qt 4.6.2 sdk
#if defined(Q_WS_WIN)
//On Windows only context menus can be activated with the right button
if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0)
#endif
d->activateAction(action, QAction::Trigger);
I don't know what the topCausedWidget() does in life but it's kind of explicit that only left button release will trigger the current action ...
One simple solution for you will be to re-implement your QMenu with this line commented ...
Sounds like you need to create your own class based on QMenu, and use it for every context menu in your program.
Check here for a reference.
I am trying to determine when the main window of my application has been moved. The main window is a standard QMainWindow and we've installed an eventFilter on the QApplication to look for moveEvents for the QMainWindow, but none are being triggered. For a variety of reasons, subclassing the QMainWindow isn't really an option.
Any thoughts on this, aside from starting a QTimer tto constantly check the position, would greatly be appreciated.
I guess it's better to install the event filter at the top-level window, instead of the application. However, if you still do not get QMoveEvents and you're working on Windows, you probably can override winEventFilter() and wait for WM_MOVE. Similar functionality might be available for Linux and Mac.
I usually do not recommend to break the platform-independence, but sometimes it might make sense.
Subclassing is really the best solution :-/
In the class that implements your top level windows you just overload this function:
virtual void moveEvent ( QMoveEvent * event )
From the documentation:
This event handler can be
reimplemented in a subclass to receive
widget move events which are passed in
the event parameter. When the widget
receives this event, it is already at
the new position.
The old position is accessible through
QMoveEvent::oldPos().
This should allow you to detect if your main window has moved. Why can't you subclass? Are you using an instance of QMainWindow directly? The usual use case is to subclass it anyway.