According to the documentation the return value from a slot doesn't mean anything.
Yet in the generated moc code I see that if a slot returns a value this value is used for something. Any idea what does it do?
Here's an example of what I'm talking about. this is taken from code generated by moc. 'message' is a slot that doesn't return anything and 'selectPart' is declared as returning int.
case 7: message((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
case 8: { int _r = selectPart((*reinterpret_cast< AppObject*(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = _r; } break;
The return value is only useful if you want to call the slot as a normal member function:
class MyClass : public QObject {
Q_OBJECT
public:
MyClass(QObject* parent);
void Something();
public Q_SLOTS:
int Other();
};
void MyClass::Something() {
int res = this->Other();
...
}
Edit: It seems that's not the only way the return value can be used, the QMetaObject::invokeMethod method can be used to call a slot and get a return value. Although it seems like it's a bit more complicated to do.
Looking through the Qt source it seems that when a slot is called from QMetaObject::invokeMethod the return type can be specified and the return value obtained. (Have a look at invokeMethod in the Qt help)
I could not find many examples of this actually being used in the Qt source. One I found was
bool QAbstractItemDelegate::helpEvent
which is a slot with a return type and is called from
QAbstractItemView::viewportEvent
using invokeMethod.
I think that the return value for a slot is only available when the function is called directly (when it is a normal C++ function) or when using invokeMethod. I think this is really meant for internal Qt functions rather than for normal use in programs using Qt.
Edit:
For the sample case:
case 8: { int _r = selectPart((*reinterpret_cast< AppObject*(*)>(_a[1])), *reinterpret_cast< int(*)>(_a[2])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = _r; } break;
the vector _a is a list of arguments that is passed to qt_metacall. This is passed by QMetaObject::invokeMethod. So the return value in the moc generated code is saved and passed back to the caller. So for normal signal-slot interactions the return value is not used for anything at all. However, the mechanism exists so that return values from slots can be accessed if the slot is called via invokeMethod.
It is Very useful when you deal with dynamic language such qtscript JavaScript QtPython and so on. With this language/bindings, you can use C++ QObject dinamically using the interface provided by MetaObject. As you probably know, just signals and slots are parsed by moc and generate MetaObject description. So if you are using a C++ QObject from a javascript binding, you will be able to call just slots and you will want the return value. Often Qt bindings for dynamic languages provides some facility to acces to normal method, but the process is definitely more triky.
All slots are exposed in QMetaObject, where the object can be accessed via a reflective interface.
For instance, QMetaObject::invokeMethod() takes a QGenericReturnArgument parameter. So I belive this is not for explicit slot usage, but rather for dynamic invocation of methods in general. (There are other ways to expose methods to QMetaObject than making them into slots.)
The invokeMethod function is, for example, used by various dynamic languages such as QML and Javascript to call methods of QObject:s. (There's also a Python-Qt bridge called PythonQt which uses this. Not to be confused with PyQt, which is a full wrapper.)
The return value is used when making syncrhonous calls across threads inside a Qt application (supported via invokeMethod and setting connection type to Qt::BlockingQueuedConnection, which has the following documentation:
Same as QueuedConnection, except the current thread blocks until the
slot returns.
This connection type should only be used where the emitter and receiver
are in
different threads. Note: Violating this rule can cause your application
to deadlock.
Related
If I am given a pointer to an object and I need to pass one of that object's methods as an argument to another function, is that possible?
A very simplified example would look like this:
void consumeAFunction(Function func) {
auto value = func();
// do some stuff //
}
void main(Object *pointerToObject) {
consumeAFunction(pointerToObject->someMethod)
}
I've tried the following, but I think my understanding of pointers and references is flawed. I'm 3 weeks old in my c++ journey.
Object someObject = pointerToObject and Object someObject = *pointerToObject
The specific context of the question is that I have a pointer to an object created by some other library and I need to use QtConcurrent::run on that object's methods.
Additional context
consumeAFunction is QtConcurrent::run
Function func is a method of an Engine that simply performs some logic. I am handed a pointer to Engine by a third party library.
I cannot avoid using a pointer to Engine, because it is all I am given to work with.
As much of the specific code as I am allowed to show:
// engine is the pointer to someObject:
auto engine = lui::QueryInterop<wise::Engine>(lui::GetLUI());
if (engine) {
connect(&m_modelsLoadedWatcher, &QFutureWatcher<bool>::finished, this, &ConfigDialog::onNNModelsLoaded);
// This is the call to consumeAFunction (qtconcurrent::run)
m_modelsLoadedFuture = QtConcurrent::run(engine->loadPytorchModels);
m_modelsLoadedWatcher.setFuture(m_modelsLoadedFuture);
Because this is a Qt question, I highly recommend you get an understanding of QObject and QMetaObject::invokeMethod().
Because QObject is pre-processing via the moc-compiler, a lot of public interfaces, such as properties, methods are exposed in such a way that the object's properties and methods can be inspected at runtime by another plugin and that it doesn't need to know or have access to the header files. This is why something like QMetaObject::invokeMethod() can work because it has access to the metadata.
Alternatively, if you are using Javascript a lot in QML, you may be interested in passing a Javascript callback function to C++. That function is accessible via QJSValue. QJSValue usually is used to hold simple types such as strings and numbers. When it holds more complex Javascript types such as arrays, objects, or functions you can use quite a few QJSValue methods to unlock their capabilities. In the case of Javascript functions you can verify if it is a Javascript function with QJSValue.isCallable() == true and can you can execute it with QJSValue.call(...).
I want to be able to send Qt signals over the network. Serializing a signal call is quite straight forward using Qt's meta type system:
Create a qMetaMethod using the static method ::fromSignal
Get the method name, parameter names, their typeIds [1] and values using the created meta method.
Pack everything into your preferred format (JSON, XML) and send it.
But so far I could not figure out how to invoke a signal using serialized data: QMetaObject::invokeMethod(..) takes the signal / method name as string. The problem are the arguments: They must be provided as QGenericArgument and those can only be created by using the Q_ARG macro which requires the actual type (not a string of it's name or the typeId) and the concerning value. Also the number of arguments must be defined at compile time, there is is no invokeMethod(..) which takes a list of arguments.
Am I missing something? Or is there a better / alternative way to do this?
[1] Further question: How do I ensure that types always get the same typeId when they are registered using Q_DECLARE_METATYPE(..)?
It is false that you can't create a QGenericArgument yourself. You're advised not to, but what you're trying to do is very implementation-dependent anyway. There isn't much to it: you provide a type name, and a pointer to the data of a given type. E.g.:
QGenericArgument one() {
static const char type[] = "int";
static const int data = "1";
return QGenericArgument{type, (void*)&data);
}
See the Introspectable Visitor section of this answer for more example code.
How do I ensure that types always get the same typeId when they are registered using Q_DECLARE_METATYPE(..)?
You don't. You should be using type names, and each process should resolve these to typeids locally.
Unless you want to implement it yourself, use something ready made, like the MIT-licensed qt-remote-signals.
You really should consider using Qt Remote Object since they accomplish everything that you need and more (heartbeat, automatic re-connection upon disconnect, works with either QLocalSocket or QTcpSocket under the hood, etc) It the easiest to get signals across the network with minimal effort that I know of.
https://doc.qt.io/qt-5/qtremoteobjects-index.html
You just need to define .rep text file, which is like an IDL definition file
class MyRemoteObject {
{
SIGNAL(foo(int value));
SIGNAL(bar(float value));
SLOT(somethingChanged(int newValue));
};
and then it takes that .rep file to generate code for the server side (known as 'source') and code for the client side (known as 'replica') using a built-in repc compiler that is called by qmake or cmake. Every signals called by the 'source' is automatically sent across every connected 'replicas', and slots called by 'replicas' are received by the 'source'
I'm trying to make a lua package using the Lua C API and LuaBridge, and I need to send data through a serial port, thus the use of Qt's QSerialPort.
The binding works fine, that is, I can use the class I registered with Lua in my scripts. However, every time I use QSerialPort::write, Qt prints tha following warning:
QObject::startTimer: Timers can only be used with threads started with QThread
I have not declared a QCoreApplication, and I do not know where I should declare it since a library doesn't have a main() function.
The closest thing I have to an entry point is
int luaopen_my_io_lib(lua_State *L);
which registers my class to Lua.
The QSerialPort is used as a member of the class I register, and constructed without a parent QObject.
How can I fix this?
[EDIT] here is the code that triggers the warning:
bool SerialIO::write(std::string data) {
m_port.write(data.c_str());
return m_port.waitForBytesWritten(100);
}
where m_port is a QSerialPort.
I think I should be able to fix it by starting a new QThread, but that would be a bit overkill for what I'm trying to achieve...
I have a C++ method made Q_INVOKABLE. I can call this method from QML and it works when it returns basic types (like QString). But I can't with a custom type. How should I do this? Should I return a QVariant instead? Ideally, I would like to return a pointer to my custom type if possible.
EDIT
I do:
qmlRegisterType<MyType>("Mine", 1, 0, "MyType");
qmlEngine->rootContext()->setContextProperty("testObj", new MyType());
I can use testObj global object or create MyType QML component. But I cannot use it in some javascript code as a return type from a Q_INVOKABLE C++ method.
This is possible but you need to define your custom type
as an interface.
First of all in your main() function:
qmlRegisterInterface<MyType>("MyType");
Now you can proceed to create an object and return a pointer
in a Q_INVOKABLE:
MyType* example = new MyType(parent);
return example;
Note: it might be beneficial to pass the parent to your custom QObject to ensure that this object is deleted together with his parent (to avoid memory leaks).
Yes, QVariant is the way to go for your custom class in that construction. Make sure you register your class.
That being said, you may wish to consider using Q_PROPERTY instead, for your custom type and then you can access that even without a function call. If you need custom parameters to the method and you cannot rearrange the code, this is obviously not an option.
Note that the target of this answer are people with a similar problem, rather than the original asker.
The described method should work, at least in recent versions of Qt (I'm using Qt 5.12, but it should work in older versions too). Maybe it was a bug in one of the first QML releases.
Checklist: Verify you have done the following:
Registered your type qmlRegisterType<MyType>("Mine", 1, 0, "MyType"); (or use qmlRegisterUncreatableType)
Imported your custom types in qml: import Mine 1.0
Derived your class from QObject.
Added Q_OBJECT to your class definition.
When returning pointers from a Q_INVOKABLE method, please take object ownership into account.
I think Dimitri's answer only applies when your type is copyable (so it wouldn't work for QObject). My understanding is that when you have a type that is being manipulated by Qt, for example if it is being returned by an invokable, the type has to be registered as a metatype:
Non-copyable types like any QObject derived model cannot be metatypes
A pointer type is a different type, therefore it needs to register separately from the classes it points to
For pointer type Foo* you can register it with metatype system: qRegisterMetaType<Foo*>("Foo*");
Consider signal manager that receives the signal, checks for some conditions, and if they are met, transmits signal to slot, discarding signal otherwise:
signal(some args) ---> [manager] ---> slot(some args)
I can implement it for each given set of arguments using QMetaObject::invokeMethod, say for void signal(int) and void slot(int):
.h
class Manager: public QObject
{
Q_OBJECT
public:
Manager(QObject* sender,const char* signal, QObject* recv, const char* slot);
private:
bool isOkToSend();
QString slotInvokeSyntax;
QObject *recv;
private slots:
On_Signal(int);
}
.cpp
Manager::Manager(QObject* sender,const char* signal, QObject* recvIn, const char* slot)
: slotInvokeSyntax(slot)
, recv(recvIn)
{
connect(sender,signal,this,SLOT(On_Signal(int));
//retrieving method name only
slotInvokeSyntax.remove(0,1).remove(QRegExp("(*",Qt::CaseSensitive,QRegExp::Wildcard));
}
Manager::On_Signal(int val)
{
//invoking slot
if(isOkToSend())
QMetaObject::invokeMethod(recv,slotInvokeSyntax.toAscii().constData(),Q_ARG(int,val));
}
I would like to somehow generalize this for signals and slots with generic number/type of arguments - so that manager works on any pairs like signal(QString)-slot(QString), signal(int,int)-slot(int,int), ...
Is there any way to implement this functionality without adding slot for each of the argument types in Manager? In case my approach is in wrong in general, any suggestions on how to implement such manager are welcome!
EDIT
A bit of clarification on what am I trying to implement - I have large system with several possible states consisting of many smaller widgets (or sub-systems) (some sub-systems can also act both as stand-alone applications or as a part of the larger system). I'm trying to implement global observer that intercepts certain ui events (such as buttons clicks, edits in QLineEdit, QDropbox changes, etc.), and either let corresponding slot of the widget to be called, or discards it if desired action interferes with the global state of the system. I would like to do it through intercepting signal since it allows to avoid dependencies between system components and compiling each subsystem as stand-alone library (with observer not being dependent on any other part of the system and thus being put in core library), but I'm open to any other alternatives that will allow me to achieve that!
FYI, whenever you use something like this:
QString foo;
something(foo.toAscii().constData());
...you are accessing already freed memory because the data pointed to by the QByteArray::constData are valid only until the QByteArray instance lives and is not modified. In your case, the QByteArray is a temporary created by calling foo.toAscii() and is destroyed before the something is called. So this will crash at some point. edit: this does not apply to function calls, see the comments.
To your question -- it would be interesting to know what you're trying to achieve here. The Qt's metatype and metaobject system is indeed a rich one, but abusing it too much might not be the most ellegant way of solving your problem. That said, it's probably fine to use it in this "creative" way with mocked objects, in unit tests etc.
I haven't done this myself and I am not sure whether it's doable without having to touch the q_static_metacall, but it looks like QObject generic signal handler contains an answer to your question.
After Edit:
You said you're looking for a something like a common event bus; the alleged reason is to avoid excess rebuilds when the individual components change. I would not introduce a central interceptor to this architecture. If the toal amount of states is reasonably small, why don't you just let something emit signals upon entering a particular state and have all of your components react to that by enabling/disabling the individual QActions?