As @mvidelgauz noticed, QAction
is abstracted from input devices which may triggered the action. Nevertheless, if the action is used in your GUI, it has one or more associated widgets: tool buttons in a toolbar, entries in menu bar and so on. These widgets act like any other widgets, so they receive events which may be filtered with the use of installEventFilter and eventFilter. These two methods are inherited from QObject
, so they are present in almost any Qt class. For example, let's create an application with QMainWindow and QAction called actionTest
. Then let's turn the main window itself into an action filter for actionTest
's associated widgets by overriding main window's eventFilter
method:
bool eventFilter(QObject *obj, QEvent *ev) {
//Catch only mouse press events.
if(ev->type() == QEvent::MouseButtonPress) {
// Cast general event to mouse event.
QMouseEvent *mev = static_cast<QMouseEvent*>(ev);
// Show which button was clicked.
if(mev->button() == Qt::LeftButton) {
qDebug() << "Left button!";
}
if(mev->button() == Qt::RightButton) {
qDebug() << "Right button!";
}
}
// In this example we just showed the clicked button. Pass the event
// for further processing to make QAction slots work.
return QMainWindow::eventFilter(obj, ev);
}
Then we need to install event filter object for all watched objects, which are widgets in our case. Let's do it in main window constructor:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
for(auto wgtPtr : ui->actionTest->associatedWidgets()) {
wgtPtr->installEventFilter(this);
}
}
Finally, add a slot for triggered()
signal handling:
void on_actionTest_triggered() {
qDebug() << "Action triggered!";
}
Now if you click the action menu entry with left mouse button, it will print
Left button!
Action triggered!
while for right mouse button the result will be
Right button!
Action triggered!
Note that widget event filtering is always performed before triggered()
signal emission.
The above code is just an example, and MainWindow
class is not the best place to host eventFilter
method. In real code you may either:
- Create dedicated
QObject
subclass(es) for QAction
widgets event filtering.
- Subclass
QAction
and override it's eventFilter
method. In this case you may just save the result of QMouseEvent::button()
in the QAction
subclass object and later use it in triggered()
signal handler. There is a minor inconvenience that Qt creator (at least up to v3.2.1) does not allow you to "promote" QAction
s in it's form designer, so you'll need to add actions to menus manually in window constructor.
- Subclass
QMenu
, QToolBar
, etc.., and make them action filters? I don't know how can it be better than two former variants.
See also documentation about Qt event system.
Let's clarify case 2. Assume the class inherited from QAction
is called MyAction
. In order to make it work you need to install MyAction
objects as filters for themselves (their widgets, to be more specific). You need to do it after widgets were created, so installing filter in MyAction
constructor may be premature and lead to crashes. Better place for filter installation is a constructor of a class which owns MyAction
object. Typically it's a widget or window class. So just add
for(auto wgtPtr : ui->myActionObject->associatedWidgets()) {
wgtPtr->installEventFilter(ui->myActionObject);
}
to your window constructor after ui->setupUi(this)
call. This code is like in the above example, but we use ui->myActionObject
instead of this
object as filter.