I'm using qt creator to create getter and setter automatically and i choose prefer getter name without "get". I find it's not working. I still got getter with "get";
like this
class A
{
int getTest() const;
void setTest(const int& test);
public:
int _test;
}
is "_test" wrong?
Related
I've a really hard time understanding what the QML_INTERFACE and QML_IMPLEMENTS_INTERFACES macros are supposed to do. Naively I assumed that the macro does what it says it does, registering a non-instantiable ("uncreatable") type to the QML type system. A type I can then use as a custom property to bind to a specific implementation.
Let's get concrete (no pun intended) and elaborate with a simple example, an interface with a single QString property:
class QmlInterface : public QObject {
Q_OBJECT
QML_INTERFACE
Q_PROPERTY(QString name READ get WRITE set NOTIFY changed)
public:
virtual ~QmlInterface();
virtual QString get() const = 0;
virtual void set(QString const& name) = 0;
signals:
void changed();
};
Q_DECLARE_INTERFACE(QmlInterface, "QmlInterface")
And a class which implements that interface (declarations omitted for simplicity):
class QmlImplA : public QmlInterface {
Q_OBJECT
QML_ELEMENT
QML_IMPLEMENTS_INTERFACES(QmlInterface)
public:
QString get() const final;
void set(QString const& name) final;
private:
QString name_;
};
An instance of this implementation is then created in C+ and an interface pointer gets passed to the QML engine right before loading the .qml file
QQmlApplicationEngine engine;
// url to .qml file
std::unique_ptr<QmlInterface> qml_impl_a{std::make_unique<QmlImplA>()};
engine.setInitialProperties({{"qml_impl_a", QVariant::fromValue(qml_impl_a.get())}});
engine.load(// url);
I then assumed I could just import the interface in my .qml file and use it with the underlying implementation like this:
import QtQuick
import QtQuick.Controls
import QmlInterface
ApplicationWindow {
required property QmlInterface qml_impl_a
// ...
}
However this doesn't work. QML complains that QmlInterface is not a type
Upon googling for some QML_INTERFACE examples I found a passage in Cross-Platform Development with Qt 6 and Modern C++ which says that:
QML_INTERFACE registers an existing Qt interface type. The type is not instantiable from QML, and you cannot declare QML properties with it.
Wait... what? Is this true? The official documentation doesn't mention this anywhere. As this would practically render interfaces completely useless I assume the book is wrong here?
For now I got my example working by making the interface a normal QML_ELEMENT and adding QML_UNCREATABLE to prevent instantiation from inside QML. This works and does what I intended in the first place. I still wonder though did I do something wrong or are the macros supposed to do something else entirely and are just named badly?
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
I have a class ArrayToolBar which has a public member commandBox and a public function createArray().
class ArrayToolBar : public QToolBar
{
Q_OBJECT
public:
explicit ArrayToolBar(const QString &title, QWidget *parent);
CommandBox* commandBox = new CommandBox();
void createArray();
Here is how createArray() is defined
void ArrayToolBar::createArray(){
commandBox->setFocus();
connect(commandBox, SIGNAL(returnPressed()), this, SLOT(commandBox->SubmitCommand()));
}
SubmitCommand() is a public slot in CommandBox class.
My problem is that I am getting an error : No such slot exists.
Is this because I have used a slot of some other class in ArrayToolBar? Is there a way around?
You can use new connection syntax with labmda expressions.
Qt has a good aricle about it. https://wiki.qt.io/New_Signal_Slot_Syntax
And final code will looks like this:
connect(commandBox, &CommandBox::returnPressed,
this, [=] () {commandBox->SubmitCommand();});
You can use lambda expressions like already mentioned.
But this should do what you want without lambda:
connect(commandBox, SIGNAL(returnPressed()), commandBox, SLOT(SubmitCommand()))
I have a class (e.g. MyEnumClass, Q_GADGET) in which I define an enum, e.g. MyEnum.
I call Q_ENUM(MyEnum) to register it to the metaobject, and register the whole class as uncreatable type to QML.
In my second class (MyObject : QObject with macro Q_OBJECT) I have a slot that consumes a MyEnum as parameter. This object is registered as regular type to QML (creatable).
I want to call the slot from QML with a value from MyEnum - this fails, as the Type MyEnumClass::MyEnum seems to be unknown.
When the enum is defined inside the class with the slot, it works fine.
MVCE
class MyEnumClass {
Q_GADGET
public:
enum MyEnum {
E1,
E2,
E3
};
Q_ENUM(MyEnum)
};
class MyObject : public QObject
{
Q_OBJECT
public:
MyObject(QObject* parent = nullptr) : QObject(parent) {}
enum TestEnum {
V1,
V2,
V3
};
Q_ENUM(TestEnum)
public slots:
void testFun1(MyEnumClass::MyEnum val) { qDebug() << val; }
void testFun2(TestEnum val) { qDebug() << val; }
};
in main.cpp:
qmlRegisterUncreatableType<MyEnumClass>("MyObject", 1, 0, "MyEnum", "Uncreatable");
qmlRegisterType<MyObject>("MyObject", 1, 0, "MyObject");
in main.qml:
import MyObject 1.0
ApplicationWindow {
id: window
visible: true
width: 600
height: 600
MyObject {
id: obj
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log(MyObject.V2)
console.log(MyEnum.E2)
obj.testFun2(MyObject.V2)
obj.testFun1(MyEnum.E1)
}
}
}
I tried to inherit MyEnumClass in MyObject to make the enum part of MyObject, I tried with different macros and functions to make the enum even more available in the MetaObjectSystem... to no avail.
I also tried to put an enum in a namespace as described here - it was also unusable for a slot.
The only way I found to have the slot called, was by removing the enum and using int as type for the parameter - which is not that nice...
How can I make this work?
Are there any tricks I am missing?
Register metatype:
qRegisterMetaType<MyEnumClass::MyEnum>();
Explanation:
From Q_ENUM( ...) documentation:
This macro registers an enum type with the meta-object system. It must
be placed after the enum declaration in a class that has the Q_OBJECT
or the Q_GADGET macro. For namespaces use Q_ENUM_NS() instead.
...
Registered enumerations are automatically registered also to the Qt
meta type system, making them known to QMetaType without the need to
use Q_DECLARE_METATYPE().
Using Q_ENUM automatically registers enum with meta-object system so you don't need to add
Q_DECLARE_METATYPE(MyEnum)
But to use enum in queued signal slot connections, properties... you need to register meta type.
As said in int qRegisterMetaType() documentation:
To use the type T in QVariant, using Q_DECLARE_METATYPE() is
sufficient. To use the type T in queued signal and slot connections,
qRegisterMetaType() must be called before the first connection is
established.
Also, to use type T with the QObject::property() API,
qRegisterMetaType() must be called before it is used, typically in
the constructor of the class that uses T, or in the main() function.
Extending #Eligijus Pupeikis' answer, In my case I got the following error:
Error: Unknown method parameter type: Parameter::Id
And solved it by registering the exact type name it was looking for:
qRegisterMetaType<Parameter::Id>("Parameter::Id");
where Parameter::Id is an enum class inside the Parameter class.
I have a class SingletonBaseClass that is defined in C++ and later extended in QML. In the qmldir file, it is marked as a Singleton:
// qmldir file
singleton SingletonClass 1.0 SingletonClass.qml
// SingletonClass.qml
import QtQml 2.0
pragma Singleton
SingletonBaseClass {
// ...
}
This is the base class:
class SingletonBaseClass : public QObject
{
Q_OBJECT
public:
SingletonBaseClass(QObject* parent = nullptr) {}
// Get the owner engine
Q_INVOKABLE void someMethodCalledFromQml()
{
QQmlEngine* ownerEngine = ?
}
// Get the single instance of the given engine
static SingletonBaseClass* instance(QQmlEngine* engine)
{
SingletonBaseClass* instance = ?
return instance;
}
};
How can I retrieve the QQmlEngine instance in SingletonBaseClass?
How can I get a pointer to my singleton instance from within a static function?
Note: I have multiple QML engine instances in my application.
[Update]: I wasn't satisfied with the suggested workarounds and so I finally contributed this patch for 1. and QQmlEngine::singletonInstance() for 2. Both changes will be available in Qt 5.12.
If you want to get the QQmlEngine you can use the contextForObject() method as I show below:
Q_INVOKABLE void someMethodCalledFromQml()
{
QQmlEngine *ownerEngine = QQmlEngine::contextForObject(this)->engine();
qDebug()<<ownerEngine;
}
singletons in qml do not have a parent so a way to access them is by creating a property, for that we create a .qml and create an object with that property as the Singleton:
qrc:/tmp.qml
import QtQuick 2.0
QtObject {
property var obj: SingletonClass
}
and then this element is accessed by the following code:
static SingletonBaseClass* instance(QQmlEngine* engine)
{
QQmlComponent component(engine, QUrl("qrc:/tmp.qml"));
QObject *item = component.create();
SingletonBaseClass *instance = qvariant_cast<SingletonBaseClass *>(item->property("obj"));
return instance;
}
In the following link we show an example.