How can i log all executions of QAction?
-
In our application we want to log all QAction executions to a log file. All Commands are called using QAction objects, and using that we would be able to reconstruct what a user did.
I originally wanted to extend QAction with a own class and just overload the triggered method, but this method is not virtual as most others of QAction.I then tried to add signals following this approach here
https://stackoverflow.com/questions/70064468/list-all-signals-emitted-from-qt-application/70066122#70066122But i am unable to get the calling QAction Element.
Is there a way to do this without adding code to each command we implemented? -
Having had only a quick look at QAction source why don‘t you overrride the event() function and do the logging before emitting the appropriate signals?
-
Having had only a quick look at QAction source why don‘t you overrride the event() function and do the logging before emitting the appropriate signals?
@DerReisende I tried that, but i dont find a matching event type:
I find 3 events related to actions:
QEvent::ActionAdded
QEvent::ActionChanged
QEvent::ActionRemoved
(https://doc.qt.io/qt-6/qevent.html)QEvent::ActionChanged will be send when executing but also when building the events or on a a language change etc. I dont find a way to distinguish this.
-
I meant
void QAction::activate(ActionEvent event):void QAction::activate(ActionEvent event) 1113 { 1114 Q_D(QAction); 1115 if (event == Trigger) { 1116 // Ignore even explicit triggers when explicitly disabled 1117 if ((d->explicitEnabled && !d->explicitEnabledValue) || (d->group && !d->group->isEnabled())) 1118 return; 1119 QPointer<QObject> guard = this; 1120 if (d->checkable) { 1121 // the checked action of an exclusive group may not be unchecked 1122 if (d->checked && (d->group 1123 && d->group->exclusionPolicy() == QActionGroup::ExclusionPolicy::Exclusive 1124 && d->group->checkedAction() == this)) { 1125 if (!guard.isNull()) 1126 emit triggered(true); 1127 return; 1128 } 1129 setChecked(!d->checked); 1130 } 1131 if (!guard.isNull()) 1132 emit triggered(d->checked); 1133 } else if (event == Hover) { 1134 emit hovered(); 1135 } 1136 }This is from Qt6 source file and maybe you should be able to properly put logging content in your override.
-
I found a rather simple solution inspired by @DerReisende.
It just uses a signal / slot. So all i had to do besides this, was
replace "new QAction" by "new MyAction" all over my program.This seems to work fine:
class MyAction : public QAction { Q_OBJECT using QAction::QAction; bool event(QEvent *e); public slots: void onTriggered(bool); }; bool MyAction ::event(QEvent *e) { if(e->type() == QEvent::ActionChanged) { static const QMetaMethod triggeredSignal = QMetaMethod::fromSignal(&CMDIAction::triggered); if(! isSignalConnected(triggeredSignal)) connect(this, SIGNAL(triggered(bool)), this, SLOT(onTriggered(bool))); } return QAction::event(e); } void MyAction ::onTriggered(bool) { gLogStream << " Action Triggered: " << text() ; } -
I meant
void QAction::activate(ActionEvent event):void QAction::activate(ActionEvent event) 1113 { 1114 Q_D(QAction); 1115 if (event == Trigger) { 1116 // Ignore even explicit triggers when explicitly disabled 1117 if ((d->explicitEnabled && !d->explicitEnabledValue) || (d->group && !d->group->isEnabled())) 1118 return; 1119 QPointer<QObject> guard = this; 1120 if (d->checkable) { 1121 // the checked action of an exclusive group may not be unchecked 1122 if (d->checked && (d->group 1123 && d->group->exclusionPolicy() == QActionGroup::ExclusionPolicy::Exclusive 1124 && d->group->checkedAction() == this)) { 1125 if (!guard.isNull()) 1126 emit triggered(true); 1127 return; 1128 } 1129 setChecked(!d->checked); 1130 } 1131 if (!guard.isNull()) 1132 emit triggered(d->checked); 1133 } else if (event == Hover) { 1134 emit hovered(); 1135 } 1136 }This is from Qt6 source file and maybe you should be able to properly put logging content in your override.
@DerReisende
As noted above, you cant override QAction::activate its not virtual. -
I found a rather simple solution inspired by @DerReisende.
It just uses a signal / slot. So all i had to do besides this, was
replace "new QAction" by "new MyAction" all over my program.This seems to work fine:
class MyAction : public QAction { Q_OBJECT using QAction::QAction; bool event(QEvent *e); public slots: void onTriggered(bool); }; bool MyAction ::event(QEvent *e) { if(e->type() == QEvent::ActionChanged) { static const QMetaMethod triggeredSignal = QMetaMethod::fromSignal(&CMDIAction::triggered); if(! isSignalConnected(triggeredSignal)) connect(this, SIGNAL(triggered(bool)), this, SLOT(onTriggered(bool))); } return QAction::event(e); } void MyAction ::onTriggered(bool) { gLogStream << " Action Triggered: " << text() ; }@stefanwoe said in How can i log all executions of QAction?:
connect(this, SIGNAL(triggered(bool)), this, SLOT(onTriggered(bool)));
Couldn't you put this connect statement (and switch to the new(ish) connect format) in the constructor of
MyAction? -
@stefanwoe said in How can i log all executions of QAction?:
connect(this, SIGNAL(triggered(bool)), this, SLOT(onTriggered(bool)));
Couldn't you put this connect statement (and switch to the new(ish) connect format) in the constructor of
MyAction? -
@stefanwoe said in How can i log all executions of QAction?:
but i failed on this
Why? What happened and how exactly did you try?
-
@stefanwoe said in How can i log all executions of QAction?:
but i failed on this
Why? What happened and how exactly did you try?