Qt: Get child controls events
In some cases you may have the need to get events before they reach your child controls. The most common example would be the need to get mouse events from a "root" control (for example a QFrame object) of all child controls inside. This way will allow the "root" control to detect if mouse buttons has been pressed/released or moved over all the control area independently if there are some child controls around.
In normal situation this will be not possible since each control can receive events only if mouse is over it (just following the mouse event example) or have focus in case of different input devices like keyboard. This mean parent control will not receive mouse event of child controls. To get through this problem Qt allow to "install" an event filer allow to receive events forwarded to a specific object. However is not enough to install this filer in the "root" object for receive events of child controls also. On the contrary this filter have to be "installed" in each child controls for redirect the event to the main object. The function to call for install the filer is the following:
void QObject::installEventFilter(QObject * filterObj)
The filter object installed (*filterObj) need to contain a method as follow:
bool eventFilter(QObject *obj, QEvent *event)
that will receive all the events received by the objects where the filter has been installed to.
Now if you create all your child object at code level this operation is easy. Simply after created the child object install the filter and redirect events to your "root" object or the other object you want to use as events collector. On the contrary this operation can not be done in case you work with windows managed through Qt Creator tool. This tool allow you to create the window using a WYSIWYG (What You See Is What You Get) editor and, in the compilation phase, generate automatically the code creating all the objects of the window (initialized through the line "ui.setupUi(this);"). This mean you don't have direct access to this code and you can not make any change since this code will be regenerated to each new compilation. An easy workaround to this would involve use the same event filter as well. In add to the mouse events we are interested in our example we'll need to manage the events connected to creation and, in case, destruction of child objects also. The code will explain better than text:
MyRootObject::MyRootObject(QWidget *parent) : QWidget(parent) { // Here install the main event filter using the root object as manager installEventFilter(this); } bool MyRootObject::eventFilter(QObject *obj, QEvent *event) { switch(event->type()) { case QEvent::ChildAdded: { QChildEvent* ce = static_cast<QChildEvent*>(event); // Install the filter to each new child object created ce->child()->installEventFilter(this); break; } case QEvent::ChildRemoved: { QChildEvent* ce = static_cast<QChildEvent*>(event); // Remove the the filter from each new child object removed ce->child()->removeEventFilter(this); break; } case QEvent::MouseButtonPress: { QMouseEvent* me = static_cast<QMouseEvent*>(event); // ..... return true; } case QEvent::MouseButtonRelease: { QMouseEvent* me = static_cast<QMouseEvent*>(event); // ..... return true; } case QEvent::MouseMove: { QMouseEvent* me = static_cast<QMouseEvent*>(event); // ..... return true; } } return QWidget::eventFilter(obj, event); }
As you can see for each new child object the event filter is installed to "forward" all event to this main root object. This mean in the same function you'll receive also mouse events (used as example but each type of events pass from here) coming from our main "root" object and all children inside. Properly casting the param you can get all info you need from dedicated object connected to the event itself (QMouseEvent in our example).
Comments
Post a Comment