I have a C++ class that is exposed to QML. The C++ class contains a function that is prefixed with Q_INVOKABLE so it can be called from QML context. Currently, the function expects a QObject and const char * that represents a slot. The function then connects up that slot to an internal C++ signal. Problem is, I don't see any way for QML to trigger this function from it's side because QML functions don't translate to the slot data qt expects. Is there a way to formulate what I am expecting between QML and C++?
Related
I just realized that I can call pretty much any function of an object that is exposed to QML. Now I am curious about Q_INVOKABLE. The Qt5 docs state:
[...] any QML code can access the following members of an
instance of a QObject-derived class:
Properties
Methods (providing they are public slots or flagged with
Q_INVOKABLE)
Signals
Since Qt5 (In C++) I can invoke any public function of a QObject like a slot, i.e. I do not have to declare them as 'public slot'. Does this mean I can call any method from QML? I cant find anything in the docs.
Yes, you have to mark your function of a QObject with Q_INVOKABLE unless it's a public slot in order to be able to call it from QML.
Both Q_INVOKABLE and the slots keyword register your function with Qt meta-system. The difference is that with Q_INVOKABLE you can return values.
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 standard c++ class, and I want one of its functions to communicate with a Qt widget's slot.
Lets say I have a function foo() in my C++ class, and I want that when ever this function gets called it signal to QWidget for corresponding slot. Since QWidget is used for display purposes
and the standard C++ class is doing something else and I want to changes visual based upon some conditions( i.e. when foo() gets called).
Is it feasible that I can make a C++ class function to trigger a slot of QWidget class?
Im trying to connect a signal to a slot and pass through a vector but im not having much luck.
res = QObject::connect(storePayments, SIGNAL(existingPurchasesResponseSuccess(std::vector<QString>)), this, SLOT(RefreshPurchasesSuccess(std::vector<QString>)));
Slot:
void RefreshPurchasesSuccess(std::vector<QString>);
void Store::RefreshPurchasesSuccess(std::vector<QString> previousPurchasesArray)
{
//do something
}
Signal:
void existingPurchasesResponseSuccess(std::vector<QString>);
vector<QString> previousPurchasesArray;
emit existingPurchasesResponseSuccess(previousPurchasesArray);
It says the signal/slot is not defined, but when I take out the vector it works, so it must be something wrong with that. Am I defining it wrong?
Thanks
If you use custom structure like std::vector<QString> you must declare and register metatype
Q_DECLARE_METATYPE(std::vector<QString>)
"Ideally, this macro should be placed below the declaration of the class or struct. If that is not possible, it can be put in a private header file which has to be included every time that type is used in a QVariant." -- Qt documentation on Q_DECLARE_METATYPE
For queued connections you may need qRegisterMetatype
qRegisterMetaType<std::vector<QString> >();
qRegisterMetaType can be called for example in main() even before QApplication::exec().
Also remember that you must use Q_OBJECT macro if your class declares any signals or slots.
"The Q_OBJECT macro must appear in the private section of a class definition that declares its own signals and slots or that uses other services provided by Qt's meta-object system."
If you have no reason to use std::vector<QString> then it would be much simpler to use QStringList, which is already known to Qt's meta-object system, provides many convenient methods to manipulate its content and as a standard Qt type will fit to non-yours slot definitions.
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.