I have the habit of writing my "propertyChanged" signals with an argument, such that the receiving end doesn't need to call the Q_PROPERTY's READ function explicitly.
I do this out of clarity and the assumption that in a QML data binding situation, no "expensive" call to the getter needs to be done to actually fetch the value, as it's already passed to QML as a signal argument.
My colleagues disagreed and said it was against "QML style", to which I responded the documentation clearly states it may have an argument that will take the new value of the underlying member:
NOTIFY signals for MEMBER variables must take zero or one parameter, which must be of the same type as the property. The parameter will take the new value of the property.
Nowhere in the documentation is it stated that the QML binding system uses this parameter to prevent an additional function call to the getter when handling the signal. I understand this call will probably be made from C++, so no "expensive" QML to C++ call will be made, but it still is an extra function call, which in principle could result in a visible performance penalty in case of many updates.
I tried inspecting the QML binding source code, but couldn't infer anything from it. I wonder if someone knows what the deal is: is the signal argument used or not?
I wonder if someone knows what the deal is: is the signal argument used or not?
Here's one way to check:
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QDebug>
class MyType : public QObject
{
Q_OBJECT
Q_PROPERTY(bool foo READ foo WRITE setFoo NOTIFY fooChanged)
public:
MyType(QObject *parent = nullptr) :
QObject(parent),
mFoo(0)
{
}
bool foo() const
{
qDebug() << Q_FUNC_INFO;
return mFoo;
}
void setFoo(bool foo)
{
if (foo == mFoo)
return;
mFoo = foo;
emit fooChanged(mFoo);
}
signals:
void fooChanged(bool foo);
private:
bool mFoo;
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
qmlRegisterType<MyType>("App", 1, 0, "MyType");
QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
return app.exec();
}
#include "main.moc"
main.qml:
import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 2.0
import App 1.0
Window {
width: 400
height: 400
visible: true
Switch {
id: fooSwitch
}
MyType {
id: myType
foo: fooSwitch.checked
onFooChanged: print("onFooChanged, foo =", foo)
// onFooChanged: print("onFooChanged myType.foo =", myType.foo)
}
}
The output when switching back and forth is:
qml: onFooChanged, foo = true
qml: onFooChanged, foo = false
So it's safe to say that the value is used and not the getter.
To see what the output would have been like if the signal argument hadn't been used, uncomment the commented out line and comment out the other one:
bool __cdecl MyType::foo(void) const
qml: onFooChanged myType.foo = true
bool __cdecl MyType::foo(void) const
qml: onFooChanged myType.foo = false
Passing the values of the changed properties in the onPropertyChanged-signal is, though possible, most surely not the QML style.
Would it be, then you should expect that at least for the basic types it is implemented, which is easily shown, it's not.
basictypes.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
id: root
visible: true
width: 400; height: 450
property int num: 5
Button {
text: num
onClicked: num += 1
}
onNumChanged: console.log(JSON.stringify(arguments), arguments.length)
}
As you can see in the output, that there are no arguments passed, when you change even one of the most basic types, such as int.
If now QML would use the optional, but rarely implemented passed value this would create overhead, as you would always need to check the existence of the argument before using it. Though a simple check is not to expensive, if it usually evaluates to false, and then you use the workaround, why do it beforehand?
Though I might not rule out, that there are any passed values in any onPropertyChanged-signals in the official realse, there are none for properties added in QML with property [type] [name]. There also none for most inherited properties (tested the Button: text, width, height).
assumption that in a QML data binding situation, no "expensive" call
to the getter needs to be done to actually fetch the value, as it's
already passed to QML as a signal argument.
Technically speaking, it is not likely that there is anything similar to what you describe. It just doesn't make sense. If your getters are expensive, you should take care to cache the result in a simpler form, and either update on changes or on demand.
If QML bindings were exclusively single property to single property, such an optimization could make sense. But bindings in QML are actually anonymous expressions, and the way it works is when any change notification for an object that is referenced by the expression triggers its reevaluation. In such a case it would add needless complexity to the implementation, having one value sent from the notification signal to keep and others which you have to call getters for.
Obviously, I am just postulating here. Another thing that makes me skeptic of the existence of such an optimization is that the property binding system isn't all that sophisticated or focused on efficiency. Which is evident from the fact that it cannot even eliminate redundant evaluations in the case of property value inter-dependencies. I've seen claims that such optimizations exist, but I've tested and it failed to avoid even the most simple of binding tree redundancies.
Naturally, if you insist on MEMBER properties, this is not so easy to prove, since the getters are auto generated, and you don't get to insert your debug statement there.
But if you try it for a regular property, you will find out that even if the signal emits the actual value, the getter is invoked nonetheless. There is absolutely no reason why an auto-generated getter would get a different treatment.
As mentioned in the linked answer, if you need the value emitted for the C++ part of the code, then keep, it it will not interfere with the QML part. If not, then simply don't emit the value, even if minuscule, it is still overhead. Emitting the value is the C++ way, bindings are a fundamentally different concept that is not really applicable in C++ (not without extensive verbosity), the QML way does not require to emit the changed value.
So your are both wrong. It is not really "against the QML style", as it will not hinder anything, and having the option to emit a value in the documentation in no way suggest that it is "in line with the QML style", or that it gets any special treatment. So if that's the reason you are doing it, you might as well stop, as it is entirely redundant.
Note that the code, generated in QtCreator by rightclicking on a property foo and selecting "Refactor/Generate Missing Q_PROPERTY Members"
Q_PROPERTY(bool foo READ foo NOTIFY fooChanged)
generates a signal containing the property
void fooChanged(bool foo);
So I would argue that this is the Qt/QML style
Related
I have a database with table X: let's call it clients. I also have a form related to editing table X contents. It may open it on it's own (to browse/edit) as well as from other forms when it is necessary to "pick" a record from table X.
How do I go about telling the parent that a particular QModelIndex has been picked straight out of on_tableView_doubleClicked(const QModelIndex &index) signal handler?
Currently, I had only one "dad" form, so I knew which type of pointer to put in child form (so it can hold a pointer to parent) and just casted a pointer of it's type.
if (parent) daddy = qobject_cast<InvoiceEd*>(parent);
Now I want to add a call from another form, I realized that I have to cast different pointer out of QWidget* pointer, and I don't know how to determine what's "in disguise" under QWidget* parent pointer. How can I do that?
I suggest using an interface and dynamic_cast to pass the information about the selected item:
InvoiceEdInterface.hpp:
class InvoiceEdInterface {
public:
virtual void SetSelectedItem (SelectedItemClass i_selected_item) = 0;
};
InvoiceEd.hpp:
class InvoiceEd: public InvoiceEdInterface {
public:
void SetSelectedItem (SelectedItemClass i_selected_item) override {
// Process setting selected item.
}
};
DataForm.hpp
class DataForm {
...
void on_tableView_doubleClicked(const QModelIndex &index) {
auto invoice_ed {dynamic_cast< InvoiceEdInterface* >(parent ())};
if (invoice_ed) {
invoice_ed->SetSelectedItem (...);
}
}
...
};
The idea behind the solution is pretty simple: if the parent widget implements the specified interface, that the SetSelectedItem() is called. Otherwise, nothing happens.
Note, however, that the proposed solution may not be Qt-ish. With Qt, you may add a signal that informs about the selected item. When the DataForm object is created in parent widget to select some item, the parent widget should establish a signal-slot connection. This solution is more flexible than the one, proposed above because it lets any object in the program get information about the selected item.
Both of the proposed solution work dynamically without the limitations of the template-based solution.
There is a code in some existing method implementation to resolve the widget type:
// dataform.cpp
void DataForm::myEdit()
{
///
if (parent()) daddy = qobject_cast<InvoiceEd*>(parent());
}
and the author wants to make it more flexible e.g. specifically cast to certain widget type depending on the caller. That can be done. Let's pass the desired type to it:
class DataForm
{
public:
// was void myEdit()
template <typename T = InvoiceEd> // defaults to InvoiceEd
void myEdit()
{
///
T* daddy = qobject_cast<T*>(parent());
// now we operate with the proper pointer so that
// exact instance does virtual function calls etc.
}
///
};
pDataForm->myEdit(); // default case
pDataForm->myEdit<MutatedInvoiceEd>(); // specified case
P.S. The above is without criticizing the design which is questionable. In OOP we don't usually want to know the context the method was called from or the objects don't want to identify each other. You should in this case create two different methods for different uses or maybe provide an additional parameter (maybe with default value void myEdit(bool insideOfContainerEdit = true) so that the code knows about some principal use case. There a number of ways to handle that but we cannot see the entire code of yours.
But of course the very existence of templates in C++ makes us able to solve the problem to degree. I myself find help in templates to sometimes avoid writing more code or derive from the type etc. but overuse of such approach leads to a lot of headache. We ideally should either rely on inheritance with polymorphism or handle such cases entirely via templates with parameter types.
When I write a new component for QML in C++, I use the macro:
Q_PROPERTY(type READ getter WRITE setter NOTIFY signal)
Here I might use different types, e.g. int or QVariant. I was wondering, if I have any benefit of not using QVariant here.
To quote the documentation:
Without QVariant, this would be a problem for QObject::property() and for database work, etc.
So - what happens if I read or write to a property on the QML side?
My guess is, that it calls:
QVariant QObject::property(const char *name) const
bool QObject::setProperty(const char *name, const QVariant &value)
which means, that my properties, neatly defined as int, dobule, QString, ... returned by my getter will be wrapped as QVariant to be transferred from C++ to QML - a process that would be unnecessary if I would have defined it as QVariant from the beginning.
If I have a Component in QML it is very likely that I have bindings from one property to multiple other properties, so reading happens quite often. So it would be a good idea to have the type in Q_PROPERTY QVariant, as otherwise I would wrap it tons of times.
On the C++-Side I might decide, whether it is read often. If so, I buffer the value in the original data type for access within C++ but create the QVariant when ever the value changes, so for QML it is unnecessary to create it multiple times. - Or is this happening automatically? Does a QML Object has all it's property values buffered as QVariant?
No, i think you don't. At least if you expose it to QML or use in any kind of subclasses from QAbstractListModel( all values there returned by data function and return type is QVariant)
I have just run my app throught debugger with breakpoints to see what happens with Q_PROPERTY variables. Just added simple code snipped in MouseArray onClicked function:
var p = ExContact.phone;
var e = ExContact.status;
phone is QString and status is qint8
Going throught breakpoints shows:
p is undefined
p becomes string
p value is assigned
e is undefined
e becomes type number
e value is assigned
Calls trace is complicated in view but I can see what the QVariant is used and QMetaType is used.
So it looks like any type exposed throught Q_PROPERTY becomes QVariant anyway..
I performed some analysis and experiments on QML that lead me to this answer, which I deem very probable:
Experiment: Add a property property var test to an object, and analyze its meta object in C++. What I found is:
The QMetaObject::property() method always returns a QVariant as described in the signature of this method, but the type of the QVariant is always set to the type of the property. This means a property int someInt results in a QVariant::int while a property var someVar results in a QVariant::QVariant - which means at least here, we have to unpack the value twice. +1 for using the best fitting property type!
Experiment: Add breakpoints to the source file of QVariant (QtCore/qvariant.h) at the line containing inline QVariant(QVariant &&other) Q_DECL_NOTHROW : d(other.d) and inline QVariant &operator=(QVariant &&other) Q_DECL_NOTHROW, which I found likely to be called when I change the value of a QVariant in QML.
In QML I added a Button which incremented its x position upon click.
As expected, when ever I clicked the Button, those two lines were called repeatedly. Unfortunately, I am missing the insight, which QVariants where changed, and whether one of them is indeed our property for the position. However I don't think that Qt will have tons of QVariants somewhere in the backend, so I deem it likely, that my assumption is true, and on the QML-side the properties are handled as QVariant.
Take home message: Though the properties in QML are handled as QVariant it is beneficial to declare the properties using a better fitting type, as otherwise the result is not a QVariant::int but maybe a QVariant::QVariant::int.
In my experiments I found no trace of QJSValues flying around which I would not have been surprised to find instead of QVariant::QVariant when having a property var ...
Suppose I have class:
class Foo : public QObject{
Q_OBJECT
public:
...
private:
Bar* m_bar;
}
And for whatever reason, I'd like to replace m_bar with a pointer to an object of DerivedBar. The use case I most often find is when I want to replace it with an object of MockBar (using the google mock framework) for unit testing.
Now I know in most cases, I could just extend the constructor to be something like:
Foo(Bar* bar, QObject* parent)
and just set m_bar accordingly.
But the problem I have is when the classes are QWidgets and I'm assembling them via Qt Designer. Imagine Foo and Bar are widgets, and Bar is placed inside of Foo from designer; their connections are also set via designer (ie, stored in the qml file). I've tried something like:
Bar* bar = foo.findChild<Bar*>();
bar = new MockBar(&foo);
(neglecting any memory leaks here, just trying to get functionality) But when I go to set expectations, it does not seem to be connected like the existing one was. Slots aren't called in response to signals. I don't think this is entirely unexpected due to the way connections are made, but I'm wondering if there's a way to get the effect I'm looking for.
(nb: for now, using qt 4.8 and gcc 4.6, which does limit some options for c++
Here's a better answer I've found: The issue for me is ultimately to do with the QWidgets generated from ui files. But since the Ui::FooWidget class is functionally just a pimpl pattern, I can create a pointer to a local copy of one, and modify Foo's constructor to allow me to optionally inject the ui implementation. If Foo is making a direct function call to BarWidget, I can replace that ui's 'barWidget' object with my MockBarWidget, and set expectations and such and perform testing. The previous answer will still satisfy to some degree when the interaction between the two widgets is one of signal/slot connections.
Previous Answer:
Here's one answer I've found so far, but I don't much like it:
Bar* bar = foo.findChild<Bar*>();
bool connectTest = QObject::connect(&foo, SIGNAL(setValue(int)), bar, SLOT(setValue(int)), Qt::UniqueConnection);
ASSERT_FALSE(connectTest);
bar = new MockBar(&foo);
connectTest = QObject::connect(&foo, SIGNAL(setValue(int)), bar, SLOT(setValue(int)), Qt::UniqueConnection);
ASSERT_TRUE(connectTest);
//... rest of test
I could probably wrap the whole thing up in some kind of helper function, and that function may be better with c++11/Qt5 where signals and slots can be method pointers. But I wonder if I'm missing an easier way to do it.
Edit: It turns out this pattern was giving me a false positive, only the first 'connectTest' part of the test was giving a valid test of behaviour. This flaw is more obvious when Foo doesn't emit a signal to bar , but merely calls a method on bar. The mock is not injected through this pattern.
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?
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.