From the docs (https://doc.qt.io/qt-5/qtqml-cppintegration-data.html#value-types) and other posts I got the impression, that Q_GADGET can be used as a value type with copy semantics.
Let's take the Actor from the docs:
class Actor
{
Q_GADGET
Q_PROPERTY(QString name READ name WRITE setName)
public:
QString name() const { return m_name; }
void setName(const QString &name) { m_name = name; }
private:
QString m_name;
};
Q_DECLARE_METATYPE(Actor)
Now I expose an Actor with Q_PROPERTY on some C++ object like this:
Q_PROPERTY(Actor actor READ actor WRITE setActor NOTIFY actorChanged)
So far, everything is fine.
Now I have some javascript code in QML (context is the C++ object on which the Q_PROPERTY actor is exposed:
{
var actorCopy = context.actor
actorCopy.name = "Tom"
}
I always assumed that the Actor-Gadget will be copied, when assigning to the javascript variable actorCopy and I change the name on a copy.
Now I set a breakpoint in the setActor function of the defined Q_PROPERTY.
What happens is, when assigning the name of the actor in javascript, the setActor method will be called.
I would not expect that, since I work on a copy.
My question is, do I have a wrong understanding of Q_GADGET or is this a bug?
I mean, if I would have a O_OBJECT instead of Q_GADGET I would not expect the setActor function being called either, since I don't assign the property.
So Q_GADGET is neither a lightweight Q_OBJECT nor a value type.
Try something like this:
{
var actorCopy = context.actor
var otherCopy = actorCopy
actorCopy.name = "Tom"
otherCopy.name = "Gatis"
}
Then in your debugger you will see that setName() is called on two different instances. You can print "this" pointer to confirm.
I did not run this code, but I think that is how it should work.
Related
I would like to have a qt QML var accessible globally, and anywhere else in my qml files. Is this possible?
I know that upon creating a variable in a C++ object can be accessed in QML by exposing its getter function, but this only works if you know the type of the data type e.g. string, int, bool.
Is there a variable data type (or class) that can handle a QML var in C++, so that I can only call it in the other parts of the QML files?
AS Amfasis said, you can use the rootContext, so you can access it from anywhere in QML - as long as you do not shadow the name. Alternatively you can also register a Singleton to QML.
For both, you first need to create a QObject
public class MyContextObject: public QObject {
Q_OBJECT
Q_PROPERTY(QVariant myVar READ myVar NOTIFY myVarChanged)
QVariant m_myVar;
public:
MyContextObject(QObject* parent = nullptr) : QObject(parent) {}
QVariant myVar() { return m_myVar; }
void setMyVar(QVariant var) {
if (var == m_myVar) return;
m_myVar = var;
emit myVarChanged();
}
signals:
void myVarChanged();
}
This object you create in your main and set it as a contextProperty
MyContextObject* mctx = new MyContextObject();
view.rootContext()->setContextProperty("myCtx", mctx);
To set it from C++ use the setter. On the QML-side just bind to myCtx.myVar
Expose the setter also, if you want to modify it from QML also
This is not tested, I don't have a Qt development environment available right now.
To expose it as singleton, you can use this function:
https://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterSingletonType-1
There is a question about how to bind from a singleton object property to a QML property. But what about if we like to bind a QML property to a singleton object.
Here is the singleton class definition,
class Singleton : public QObject {
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
public:
explicit Singleton(QObject *parent = nullptr);
QString name() const;
void setName(const QString &name);
private:
QString m_name;
};
And on QML
property string qmlName: textField.text
TextField {
id: textField
}
I would like to bind textField.text to Singleton object name property. It is possible to bind it with a workaround like,
onQmlNameChanged: {
Singleton.name = qmlName;
}
But that won't be an Property Binding actually, because it is an assignment.
So is there a more nature binding way to a singleton object property?
You could try to assign the binding like this:
Component.onCompleted: Singleton.name = Qt.binding(function() { return qmlName })
It works for normal QML-Objects, not sure it works with a singleton class, though. Anyhow, you can read more about this approach in the section "Creating Property Bindings from JavaScript".
That is essentially what a property binding does, at least I assume it is what it does - it connects the changed() signals of the related variables to reevaluating the bound expression which references them.
So this in practice is a binding:
onQmlNameChanged: {
Singleton.name = qmlName;
}
You will only have a problem if you only execute the assignment once, but if it is attached to a signal it will keep updating as expected form a binding.
That would be identical to a Singleton.name : qmlName, unfortunately, the QML syntax does not allow to do it in this form. So for all intents and purposes, you do have a binding, even if it uses a different syntax to achieve it.
In fact this shouldn't be much different from what QML does under the carpet for you. For example the binding:
someProp : anotherProp + yetAnotherProp
is implement as something like this:
function unnamed(this) { return this.anotherProp + this.yetAnotherProp }
anotherPropChanged.connect(function(this) { this.someProp = unnamed(this) })
yetAnotherPropChanged.connect(function(this) { this.someProp = unnamed(this) })
Obviously, that is quite cumbersome to do manually especially as the expression becomes more complex and references more objects, so QML is doing it for you.
Generally, a lot of code does nothing but get/set class members. For that I implemented a simple container class to have getters and setters associated
to a "field". At a first sight this looks pretty ok and results in far less code. This is how the container class looks like:
Member.h
#include <functional>
template <class T>
class Member
{
public:
T data;
using Getter_t = std::function<T(void)>;
using Setter_t = std::function<void(T)>;
using Notify_t = std::function<void(void)>;
Setter_t m_setterFunc;
Getter_t m_getterFunc;
Notify_t m_notifyFunc;
Member()
{
this->m_getterFunc = [=] (void) -> T { return this->data; };
this->m_setterFunc = [=] (T data) -> void { this->data = data; };
this->m_notifyFunc = [] (void) -> void { };
}
auto get() -> T { return this->m_getterFunc(); }
auto set(T data) -> void { this->m_setterFunc(data); this->m_notifyFunc(); }
auto getter(Getter_t func) -> Member& { this->m_getterFunc = func; return *this; }
auto setter(Setter_t func) -> Member& { this->m_setterFunc = func; return *this; }
auto notify(Notify_t func) -> Member& { this->m_notifyFunc = func; return *this; }
~Member() { }
};
I know some things are not perfect yet but that's okay for now. The next few lines show how Member instances are defined and the simple and convenient way to access underlying data. get, set and notify functions can be replaced by lambdas or function pointers to override custom behavior.
main.cpp
#include <iostream>
#include "Member.h"
class MyClass
{
public:
Member<int> foo;
Member<std::string> bar;
void barChanged() { std::cout << "bar changed\n"; }
};
auto main(int argc, const char * argv[]) -> int
{
MyClass instance;
instance.foo.notify([] () -> void { std::cout << "foo changed\n"; });
instance.bar.notify(std::bind(&MyClass::barChanged, instance));
instance.foo.set(10);
instance.bar.set("some string");
std::cout << instance.foo.get() << " " << instance.bar.get() << std::endl;
return 0;
}
The problem now is that the Q_PROPERTY macro expects function names for the READ and WRITE accessors and I'm back at where I started: I have to write get and set functions for each property explicitly. Exactly what I wanted to avoid.
class MyOtherClass : public QObject
{
Q_OBJECT
Q_PROPERTY(bool flag READ getFlag WRITE setFlag NOTIFY flagChanged);
public:
Member<bool> m_flag;
auto getFlag() -> bool { return m_flag.get(); }
auto setFlag(bool flag) -> void { this->m_flag.set(flag); }
};
Is it possible to directly use the already existing m_flag.get and m_flag.set functions? I tried the obvious things but they were either rejected by the moc or resulted in too much code.
Edit
As mentioned below, the MEMBER keyword makes it possible to have properties without specifying get and set functions. However, private members then only can be accessed by their names (this->property("myPropertyName")) and also there's no way to achieve more than "plain" get and set.
To make it more clear: The motivation is not to just avoid writing get and set functions but trying to implement a flexible member system which
by default performs get/set as expected
supports custom logic (for example forward newly set values to some other instance)
can be used for C++ class members and is compatible with Qt properties
And the only missing piece is the bridge between the Q_PROPERTY READ/WRITEaccessors and the get/set methods of the Member class.
Thanks for any help!
I don't think that it's possible to redirect READ or WRITE property methods to some other internal or external object without writing wrappers, but if your getters and setters do not do anything except return or set data: there is MEMBER variable association at least in latest Qt versions.
From Qt Doc:
Q_PROPERTY(type name
(READ getFunction [WRITE setFunction] |
MEMBER memberName [(READ getFunction | WRITE setFunction)])
[RESET resetFunction]
[NOTIFY notifySignal]
[REVISION int]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])
A READ accessor function is required if no MEMBER variable was
specified. It is for reading the property value. Ideally, a const
function is used for this purpose, and it must return either the
property's type or a const reference to that type. e.g.,
QWidget::focus is a read-only property with READ function,
QWidget::hasFocus().
A WRITE accessor function is optional. It is for setting the property
value. It must return void and must take exactly one argument, either
of the property's type or a pointer or reference to that type. e.g.,
QWidget::enabled has the WRITE function QWidget::setEnabled().
Read-only properties do not need WRITE functions. e.g., QWidget::focus
has no WRITE function.
A MEMBER variable association is required if no READ accessor function
is specified. This makes the given member variable readable and
writable without the need of creating READ and WRITE accessor
functions. It's still possible to use READ or WRITE accessor functions
in addition to MEMBER variable association (but not both), if you need
to control the variable access.
Using MEMBER you do not need to write getters and setters.
In C++11, two types of "managed" pointer types were introduced - shared_ptr and unique_ptr. Let's now assume we have a set of classes that support a clone() method, such as foo->clone() would return a copy of the foo object. If your goal was to return a managed pointer from the clone() method, how would you allow the user of the interface to select which kind of pointer he wants to be returned?
As a sub-question, would you rather return a raw pointer from the clone() method and let the user construct either shared_ptr or unique_ptr by himself? If not, why?
The standard smart pointer to manage a dynamic allocation is always unique_ptr. By contrast, shared_ptr is a very specific tool with specialized features (e.g. type-erased deleter, weak pointer observers) and higher costs (virtual dispatch, locked atomic operations) that should only be used when you definitely know you want it. Public raw pointers are a taboo out of principle, and so the natural clone interface looks like this:
struct Base
{
// must have virtual destructor to destroy through base pointer
virtual ~Base() {}
// non-leaf classes are abstract
virtual std::unique_ptr<Base> clone() const = 0;
};
struct Derived : Base
{
virtual std::unique_ptr<Base> clone() const override
{
return std::unique_ptr<Derived>(new Derived(*this));
// or "return std::make_unique<Derived>(*this)" in C++14
}
};
(Unfortunately, we cannot use any kind of covariant return types here, since the template classes unique_ptr<Base> and unique_ptr<Derived> are unrelated. If you prefer to have a clone function that returns the derived type, you could add a non-virtual function like direct_clone that returns a std::unique_ptr<Derived>, and implement the virtual clone() in terms of that.)
Something along this lines would give you the means to select the kind of smart pointer returned. Would probably be better if encapsulated in a mixin Clonable class template, for maintainability and reusability of the idea.
#include <iostream>
#include <memory>
class Base {
public:
virtual ~Base() {
std::cout << "deleting Base\n";
}
template <template <typename ...Args> class SmartPtr>
SmartPtr<Base> clone() {
return SmartPtr<Base>(this->inner_clone());
}
virtual void speak() const = 0;
private:
virtual Base *inner_clone() const = 0;
};
class C: public Base {
public:
~C() {
std::cout << "deleting C\n";
}
template <template <typename ...Args> class SmartPtr>
SmartPtr<C> clone() {
return SmartPtr<C>(this->inner_clone());
}
void speak() const {
std::cout << "I am C and I inherit from Base!\n";
}
private:
C *inner_clone() const override {
return new C(*this);
}
};
// End boilerplate.
int main()
{
auto original = C{};
// the declarations below should use auto, and are just explicitly typed to
// show the correct return type of clone();
std::shared_ptr<C> shared = original.clone<std::shared_ptr>();
std::unique_ptr<C> unique = original.clone<std::unique_ptr>();
// the declarations below show it working through conversion to a base class
// smart pointer type
std::shared_ptr<Base> sharedBase = original.clone<std::shared_ptr>();
std::unique_ptr<Base> uniqueBase = original.clone<std::unique_ptr>();
// the declarations below show it working through the base class for real
std::shared_ptr<Base> sharedBaseFromBase = sharedBase->clone<std::shared_ptr>();
std::unique_ptr<Base> uniqueBaseFromBase = uniqueBase->clone<std::unique_ptr>();
shared->speak();
unique->speak();
sharedBase->speak();
uniqueBase->speak();
sharedBaseFromBase->speak();
uniqueBaseFromBase->speak();
}
Compiles with gcc 4.8.1, and should in any compiler supporting variadics.
I would still prefer to simply return a unique_ptr and move the result into a shared_ptr, which would be automatic since the call to clone() is in itself an rvalue.
(C++/Qt) I have a smart pointer to a QObject. Let's say a QWeakPointer. For some external reason (something that might happen in another object or due to an event), it is possible that the pointed object gets destroyed. Since I have a smart pointer there will be no dangling reference, so there's no problem. But I always have to check if the pointer is null or not.
I'm thinking of using the null pattern in order to avoid checking this all the time but I'm not sure if this is possible or convenient with a QObject. The idea would be that the pointer points to the object and in case it gets destroyed, the smart pointer changes its pointed object to a null object. Is this a good idea or should I forget it and just check if the pointer is NULL all the time?
Let's show you an example. We have a worker who uses a tool to do its work:
class Worker : public QObject
{
Q_OBJECT
public:
Worker(QObject *parent = 0);
void work()
{
if(m_tool)
m_tool->use();
emit workCompleted();
};
signals:
workCompleted();
public slots:
void setTool(QWeakPointer<Tool> tool);
private:
QWeakPointer<Tool> m_tool;
};
class Tool : public QObject
{
Q_OBJECT
public:
Tool();
public slots:
void use() =0;
};
class Screwdriver : public Tool
{
Q_OBJECT
public:
Screwdriver() : Tool();
public slots:
void use()
{
// do something
};
};
class Hammer : public Tool;
class Saw : public Tool;
...
In this case, the Tool is a public domain object of a library, which is used by the Worker. I'm developing such library. So the worker is using a screwdriver but it gets broken and gets destroyed. No problem:
if(m_tool)
m_tool->use();
emit workCompleted();
m_tool is 0 so it simply does nothing. But we have to check that it's not null everytime.
Now let's say we had a NullTool object:
class NullTool : public Tool
{
Q_OBJECT
public:
NullTool() : Tool();
public slots:
void use()
{
// does nothing
};
};
When the tool was destroyed, our pointer would be smart and would know it should point to a NullTool instance. So Worker::work() could be implemented like this:
void Worker::work()
{
m_tool->use();
emit workCompleted();
};
m_tool->use() would then get called on the NullTool which does nothing, so there would be no need to check the pointer is not null.
Is this a good idea? Is it possible with the smart pointer classes Qt provides or should I subclass QWeakPointer?
I think the null object pattern makes most sense for value-like classes. Examples are QString or QVariant, were you don't want to have code like if ( str && !str->isEmpty() ) but just do if ( !str.isEmpty() ). For QObjects, which are not values but have "an identity", I never found this useful.
I don't understand clearly your use case, but your program can be signaled when the object has been destroy by connecting the following signal from QObject:
void destroyed ( QObject * obj = 0 );
I don't see any problem in your idea. You just have to compare the work that it takes to implement it compared to the work for checking the pointer every time. Let's your checking the pointer 10.000 times it's a good idea to use your approach. Side note: Your null object pattern rely on the fact that Tool::use() has no side effects whatsoever.
Take care that possible side affects in Tool::use() don't get in the way when you replace it polymorphically with NullTool::use(). In other words: Be sure you don't break the Liskov Substitution Principle.