Qt: alternative to QMetaObject::invokeMethod - qt

In Qt, I often use something like QMetaObject::invokeMethod(this, "myMethod", Q_ARG(bool, foo)) (effectively, this causes the method call + args to be queued and later executed on the correct event queue).
Is there a way to use method references instead of using the method name as string (i.e. use &MyClass::myMethod instead of "myMethod"), while still queueing execution?

Since Qt 5.10 there are two QMetaObject::invokeMethod overloads which accept functor or a pointer to a member function as an argument.
Inside the same thread you can use QTimer::singleShot overload accepting functor (since Qt 5.4) and use zero milliseconds timeout.

Related

What is the functional difference between these two qt signal-slot connections?

I'm using Qt 5.9.2 with Visual Studio 2015 and QtDesigner for programming a Windows GUI application. I tried connecting one of my actions via the following call:
connect(ui.myAction, &QAction::triggered, memberPtrToObjX_, &ClassX::Run);
However ClassX::Run is not always triggered after clicking on myAction in the menubar. Investigating into this problem, I figured, that the same signal-slot connection using lambda syntax works:
connect(ui.myAction, &QAction::triggered, [this](bool run) { memberPtrToObjX_->Run(run); });
I'm pretty sure, that both calls are syntactically correct. Besides both calls return a valid QMetaObject::Connection, if I save the return value and check with operator bool().
Obviously I could just stick with the working lambda-version, but I'm confused and would prefer knowing the reason behind my "solution". Is there any functional difference between these two calls, that explains the different behaviour?
The two calls of QObject::connect() (exposed by the OP) behave differently in the case that this->memberPtrToObjX_ is modified after the call of connect().
The first
connect(ui.myAction, &QAction::triggered, memberPtrToObjX_, &ClassX::Run);
calls
QMetaObject::Connection QObject::connect( const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection).
Creates a connection of the given type from the signal in the sender object to the method in the receiver object. Returns a handle to the connection that can be used to disconnect it later.
Hence, the current pointer in this->memberPtrToObjX_ is connected as signal receiver. If this->memberPtrToObjX_ is modified after connect() this doesn't have any effect to the signal connection.
The second
connect(ui.myAction, &QAction::triggered, [this](bool run) { memberPtrToObjX_->Run(run); });
calls
QMetaObject::Connection QObject::connect( const QObject *sender, PointerToMemberFunction signal, Functor functor).
Creates a connection from signal in sender object to functor, and returns a handle to the connection.
Hence, the (functor behind the) lambda is connected as receiver. The lambda resolves the pointer in this->memberPtrToObjX_ at the time it is executed i.e. when the signal is triggered.
The second difference (which originally was uncovered in the comment of G.M.) is the connection type:
The first version uses the default value Qt::AutoConnection (as it is not defined explicitly). The version with the lambda uses always Qt::DirectConnection instead.
The difference appears if the pointee in this->memberPtrToObjX_ does not "live" in the same thread. In this case, the Qt::AutoConnection is resolved to Qt::QueuedConnection instead of Qt::DirectConnection.
I assumed that the pointee in this->memberPtrToObjX_ would "live" in the same QThread. If not, the second version (with the lambda) becomes very questionable as it calls the a member function of the object "living" in a different thread (where it is hard to tell what that thread is doing at this time). This only seems to work better but is very possibly a "time bomb".

QMetaObject::invokeMethod alternative with compile-time checking

Besides QMetaObject::invokeMethod is there any type-safe way of invoking a method/slot asynchronously (a.k.a queuing its execution in the GUI thread)?
The QMetaObject::invokeMethod doesn't have compile-time checking for function names. There is also an overhead in specifying the member function by a string since a lookup and string matching is performed for every call.
I wonder if there is anything similar to the new QObject::connect syntax for invoking a method that provides compile time checking.
One solution is using the signal-slot architecture, but this enforces wrapping each caller code in a QObject class to be able to emit that signal.
It is possible to use the QTimer::singleShot for this purpose
QTimer::singleShot(0, object, &Object::method...);
--
QTimer::singleShot(0, object, [object](){
object->method(arg1, arg2, ...);
});
Note: The thread in which QTimer::singleShot is invoked must have an QEventLoop.
Please see this https://doc.qt.io/qt-5/qmetaobject.html#invokeMethod-4
template <typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject *context, Functor function, FunctorReturnType *ret)
This is an overloaded function.
Invokes the function in the event loop of context using the connection type Qt::AutoConnection. function can be a functor or a pointer to a member function. Returns true if the function could be invoked. Returns false if there is no such member or the parameters did not match. The return value of the function call is placed in ret.
Note: This function is thread-safe.
This function was introduced in Qt 5.10.

How is the clojure.lang.Reflector used in implementation of interop methods

When we run
(.someMethod obj arg1 arg2 arg3)
is the clojure.lang.Reflector class used all the time and how does that affect performance?
That depends on whether the compiler can statically determine which class or interface someMethod belongs to.
If it can, then it will emit a direct call and c.l.Reflector will not be used at runtime. The result is equivalent to
((Foo) obj).someMethod(arg1, arg2, arg3);
in Java, assuming someMethod has been declared by the class / interface Foo.
If it cannot, then it will emit a call to the static method clojure.lang.Reflector.invokeInstanceMethod. In Clojure notation, the emitted call could be written
(clojure.lang.Reflector/invokeInstanceMethod
obj "someMethod" (object-array [arg1 arg2 arg3]))
This looks up the matching method through the use of reflection at runtime. The slowdown relative to a statically resolved call is quite spectacular.

QT - Understanding following lambda expression for a SLOT

I am currently trying to understand the new QT5 signal/slot syntax
connect(sender, &Sender::valueChanged, [=](const QString &newValue) {
receiver->updateValue("senderValue", newValue);
});
Now my question is where is the address of the receiver SLOT in the above expression ? I wanted to know this because what happens if a signal is in threadA and the slot is in thread B and I wanted it to be a queued connection ?
A slot is a piece of code, it doesn't "live" in a thread - a thread might run it or not, but the code itself doesn't belong to any thread. (If the slot is a member function, then the Qt object defined as the receiver belongs to a Qt thread - that's a property of the object, not the function.)
In the code you have above, the compiler generates an object that:
captures receiver by value ([=])
has a function-call operator that can be called with a reference to a const QString.
That object is passed to connect along with the other two arguments. It's not a QObject, so it doesn't have an owning thread in the Qt sense. What you need to make sure of is that:
what receiver points to stays alive for as long as that signal is connected
receiver->updateValue(...) is thread-safe - it will be called in sender's context/thread.
If receiver->updateValue needs to be called in receiver's thread/context, then do not use that syntax for the connect call, use the one where you specify both sender and receiver, and the connection type.

Can I pass an argument to the slot function when using QObject::connect?

Qt4.8.5
QObject::connect(button,SIGNAL(clicked()),label,SLOT(setText("dd"));
The Qt Creator tell me It's wrong . What's the problem ?
That you can't pass arguments in a connect() statement. You need a "trampoline" slot that sets the text of your label (or, in Qt 5, you might choose to use a lambda).
For instance, by using a subclass:
class MyLabel : public QLabel {
Q_OBJECT
public slots:
void setTextToFoo() { setText("foo"); }
};
// ...
connect(button,SIGNAL(clicked()),label,SLOT(setTextToFoo());
It depends what exactly you are trying to achieve, to be honest, the example code you provided is not very functional, is "dd" a particular static value you are using, or potentially some other string? Where does it come from, is it in the scope of the called, or is it sent by the caller, which is the usual practice when sending arguments to slots.
Either way, in order to make a connect statement the first requirement is for the arguments to match, clicked() has no arguments while setText() has one, so there is a mismatch. As of how to resolve that mismatch, the easiest way is to use simple wrappers, although you can use a QSignalMapper and as of Qt5, lambdas and std::bind.
For starters, you cannot specify the actual argument instance in the connect statement, even with arguments on both sides you only need to specify the types to help resolve overloads (it is terrible with the new connection syntax in Qt5), and not any actual identifiers or literals.
In case of the more usual scenario, where the data is send to the slot by the caller, the identifier or literal is specified in the emit signal(value) statement. Since you don't have clicked(const QString &) you need a wrapper slot that you connect to clicked() and emit with the value in that wrapper slot, or subclass the button and add your own overload of clicked(QString).
In case the value is in the scope of the called, then subclassing doesn't make much sense, all you need is the wrapper slot in the scope of the called object.
If you want more, you will have to use Qt 5, whose syntax is significantly more powerful.
If the question is whats wrong, just remember the parameter number must be the same for the Signal and the Slot. Asking a collegue and according the Peppe, setText(QString) wait for One parameter and the Clicked() is empty...A custom slot is to call the setText() method indirectly.
You can look that : http://qt-project.org/doc/qt-4.8/widgets-calculator.html
It uses the QWidget, an important part of Qt interfaces beside QML.

Resources