Qt QML Singleton Intellisense - c++

Qt QML, they do work, but no intellisense in QML references. Can I achieve intellisense?
pragma Singleton
import QtQuick 2.0
import QtQuick.Window 2.3
Item {
property int iMode: 0
property bool bSwapLeftRight: false
Registering it:
qmlRegisterSingletonType(QUrl(QLatin1String("qrc:/GlobalSettings.qml")), "ncs.global", 1, 0, "SingletonSettings" );
Second example;:
ctxt->setContextProperty("someModel", QVariant::fromValue(ownModel));
ctxt->setContextProperty("globalControl", QVariant::fromValue(globalControl.Get()));
First one i achieve IntelliSense in QML whilst using, the second one is the singleton, I do not achieve IntelliSense. Planning to expose some c++ defined enums to QML through this one, but looses value when no IntelliSense is provided..
Question is basically, do Qt Quick and Creator support IntelliSense for singleton classes ? Worthwhile investigating further?
Adding some more details, main question is NOT about enum's, but IntelliSense (auto-complete):
A few snippets:
main.cpp:
//Regular Pointer
SomeModel* ownModel = new SomeModel();
//Custom Singleton implementation
GlobalControlSP globalControl = GlobalControl::GetInstance();
//I did not really want this line. GlobalControl should be singleton, how would this be threated?
qmlRegisterType<GlobalControl>("ncs.global", 1, 0, "Global");
//Registering a "Pragma Singleton" file, Intellisense do not work
qmlRegisterSingletonType(QUrl(QLatin1String("qrc:/GlobalSettings.qml")), "ncs.global", 1, 0, "SingletonSettings" );
QQmlApplicationEngine engine;
QQmlContext* ctxt = engine.rootContext();
//Regular context property, not singleton. Intellisense works
ctxt->setContextProperty("ownModel", QVariant::fromValue(ownModel));
//Registering the singleton as context property, Intellisense do not work
ctxt->setContextProperty("globalControl", QVariant::fromValue(globalControl.Get()));
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
globalcontrol.h:
class GlobalControl : public QObject,
{
Q_OBJECT
Q_PROPERTY(QString backcolor READ backcolor NOTIFY backcolorChanged)
....
public:
GlobalControl(QObject *parent = nullptr);
QString backcolor() const { return m_backColor; }
....
enum EnButton
{
DEVICE_START,
DEVICE_IR,
.....
};
Q_ENUM(EnButton)
public slots:
void changeMode(int mode);
void buttonPressed(int button);
some qml file:
//This implementation works:
NcsButton {
property int valuent
id:ir
text: qsTr("IR")
width: 66 * widthScaling
Layout.row: 4
Layout.column: 1
fontColor: bIr ? valueColor : textColor
onClicked: {
globalControl.buttonPressed(Global.DEVICE_IR)
//This does not work:
NcsButton {
id:ir
text: qsTr("IR")
width: 66 * widthScaling
Layout.row: 4
Layout.column: 1
fontColor: bIr ? valueColor : textColor
onClicked: {
globalControl.buttonPressed(globalControl.DEVICE_IR)

Solution or workaround:
For QML defined singleton, add to Qt compiler QML library a generated file
..\..\..\bin\qmlplugindump -relocatable ncs.global 1.0 > plugins.qmltypes
For c++ registered singleton, make a "fake" pointer of normal class type. Register. To retrieve the enum from same singleton class, create a UncreatableType:
GlobalControlSP globalControlOrig = GlobalControl::GetInstance();
GlobalControl* globalControl = globalControlOrig.Get();
ctxt->setContextProperty("globalControl", QVariant::fromValue(globalControl));
qmlRegisterUncreatableType<GlobalControl>("ncs.global", 1, 0, "Global", "Singleton");

Related

QVector or list of custom type(s) from C++ to QML

After days of experimenting I surrender returning a list of custom objects to QML. I don't want to use QVariantList or any list creating a QVariant, as I'd like to preserve the custom objects structure and also allow using the signals from it (CItem).
CTest.h
class CTest : public QObject
...
Q_INVOKABLE QVector<CItemWrapper> getAllItems();
CTest.cpp
QVector<CItemWrapper> CTest::getAllItems(){ // tried std::vecotor, QList, ...
return {CItemWraper(...)};
};
CItemWrapper.h
class CItemWrapper: public QObject {
Q_OBJECT
Q_PROPERTY(QString title READ getTitle WRITE setTitle NOTIFY titleChanged)
Q_PROPERTY(CItem * item READ getSignal WRITE setSignal NOTIFY signalChanged)
...
Q_DECLARE_METATYPE(CItemWrapper)
CItem.h
class CEntry : public QObject{
Q_OBJECT
Q_PROPERTY( EValueStatus status READ getStatus NOTIFY statusChanged )
Q_PROPERTY( QString displayValue READ getDisplayValue NOTIFY displayValueChanged )
...
Q_DECLARE_METATYPE( CItem )
main.cpp
qmlRegisterType<CItem>( "Test", 1, 0, "CItem" );
qmlRegisterType<CItemWrapper>( "Test", 1, 0, "WrappedItem" );
std::unique_ptr<CTest> test = std::make_unique<CTest>( *wrappedItems );
view->rootContext()->setContextProperty( "TEST", test.get() );
main.qml
import Test 1.0
Repeater{
model: TEST.getAllItems()
delegate: Text{
text: modelData.title + " " + modelData.item.status
}
}
Will result in ERROR: Unknown method return type QVector<CWrappedItems> and I couldn't find any way to overcome this. Consulting the QT online help I feel like that I'm doing anything needed to register a type to the QT system.
Do you have any hints?

Threaded renderer in QML

Threaded renderer is not working in the following code. I'm using Qt 5.4 on Arch linux-3.14 with proprietary drives.
---------- mytext.h -----------
#include <QObject>
class Thing : public QObject {
Q_OBJECT
Q_PROPERTY(int qm_no READ qm_no NOTIFY qm_noChanged)
public:
Q_INVOKABLE void loop();
int qm_no();
signals:
void qm_noChanged();
private:
int m_no;
};
---------- mytext.cpp ----------
#include "mytext.h"
#include <unistd.h>
int Thing::qm_no() {
return m_no;
}
void Thing::loop() {
while(true) {
m_no += 1;
emit qm_noChanged();
usleep(1000000);
}
}
--------- main.cpp -----------
#include <QQmlContext>
#include <QQuickView>
#include <QGuiApplication>
#include <QtQml>
#include "mytext.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
Thing myTh;
QQuickView view;
view.rootContext()->setContextProperty("qmyTh",&myTh);
view.setSource(QUrl::fromLocalFile("main.qml"));
view.show();
return app.exec();
}
------- main.qml ----------
import QtQuick 2.0;
Rectangle {
id: root
width: 200
height: 200
property var name: "test"
Text {
anchors.fill: parent
text: name
}
MouseArea {
anchors.fill: parent
onClicked: {
qmyTh.loop()
}
}
Connections {
target:qmyTh
onQm_noChanged: {
name = qmyTh.qm_no;
}
}
}
Explanation::
There is a classes Thing , with its object myTh. The function of class Thing is to provide an invokable function which here is loop. This function will then continuously update the m_no value and emit signal. Now the question is that how can I update the Text (name property) while the infinite loop is running which keeps on updating the value to be displayed ?
The code is correct for what concerns the QML part (now) and it works correctly. What is not correct is the C++ implementation. if you remove the while loop, leaving its content, and execute your code you'll see that the text is correctly updated.
The reason of such behaviour should be researched in the Qt quick render implementation. On certain platforms the render is not threaded by default. I guess you are working on Windows (see "Qt Quick" here). Hence, in a not threaded setting, by updating the variable and then sleeping, you are blocking the whole application, preventing the gui update.
You can use a QTimer to schedule the method execution at intervals, or set up a QML Timer for the exact same purpose.
Also, you don't need to save the new value in a temp variable (especially a var one which adds useless checks in this case). By setting an id inside the Text element you can directly set the text property. Here the revisited code:
import QtQuick 2.0;
Rectangle {
id: root
width: 200
height: 200
Text {
id: myText // the id!
anchors.fill: parent
text: "dummy" // dummy text || left empty || use "qmyTh.qm_no" (ensure a correct value is returned at creation time)
}
MouseArea {
anchors.fill: parent
onClicked: {
qmyTh.loop()
}
}
Connections {
target:qmyTh
onQm_noChanged: myText.text = qmyTh.qm_no // text directly set!
}
}
EDIT
It seems like the used render is threaded, hence my reasoning does not apply. There should be other problems. You can try to track down the problem exploiting the debugger and by adding console.info(...) statements in the JS handlers. Searching for the problem could be useful to track (possible) bugs in the libraries.
Depending on the background processing you have to run, I still think that using timers wouldn't be that bad. It really, truly depends on what you want to achieve. However, if you want to try threads, Qt documentation is full of explanations (as usual).
Have a look at this, this
and also absolutely this. Mind that a "moved" object (see the links) cannot be registered as a context property so you have to use one of the other ways to work with threads in a QML project.

Properties combination in Qt stylesheet

I wrote Qt4 (or Qt5) class MyButton and defined two boolean properties, like this:
#include <QPushButton>
class MyButton : QPushButton
{
Q_OBJECT
Q_PROPERTY(bool property_1 READ property_1)
Q_PROPERTY(bool property_2 READ property_2)
public:
explicit MyButton(QWidget *parent = 0);
...
}
Now I want to customize application stylesheet in external file so that in different combinations of this properties MyButton has different background color. Separately this works well:
MyButton[property_1="true"] { background-color: black }
MyButton[property_2="true"] { background-color: white }
So the question is: how to combine few properties in the same condition with "and", "or" and "not" operations?
Finally I got the solution. The idea is the same as CSS attribute selection.
Thus property_1="true" AND property_2="true" condition is:
MyButton[property_1="true"][property_2="true"] { background-color: green; }

QML failing to detect QObject destroyed in C++

The presented code does the following:
<1> Create object of QObject derived class and expose it to QML
<2> The class has a pointer to another QObject derived class and the pointer is accessible to QML via Q_PROPERTY.
<3> MouseArea in QML detects user-click and simply asks the c++ code for the pointer to be deleted.
<4> Color of rectangle turns black once this is detected.
The problem is that while certain approaches detect the deletion of the pointer by c++ other approaches don't.
Look at the inline comments:
Combination of (1) and (1b) works
Combination of (1) and (1d) does not work
(2) alone by itself works but (3) alone by itself does not.
When things work you should see the color of the Rectangle turn to black from yellow.
Can someone please explain this behaviour?
CPP codes:
class Name : public QObject
{
Q_OBJECT
Q_PROPERTY(bool boolVal READ boolVal CONSTANT FINAL)
public:
bool boolVal() const {return true;}
};
class Root : public QObject
{
Q_OBJECT
Q_PROPERTY(QObject* name READ name CONSTANT FINAL)
public:
QObject* name() const {return m_pName;}
Q_INVOKABLE void deleteName() {delete m_pName; m_pName = 0;}
private:
Name *m_pName {new Name};
};
//--- main
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
Root objRoot;
QtQuick2ApplicationViewer viewer0;
viewer0.rootContext()->setContextProperty("objRoot", &objRoot);
viewer0.setMainQmlFile(QStringLiteral("qml/dualWindowApp/main.qml"));
viewer0.showExpanded();
return app.exec();
}
QML Code:
import QtQuick 2.0
Rectangle {
width: 360
height: 360
color: "red"
Rectangle {
id: objRect
anchors {left: parent.left; top: parent.top}
height: 70; width: 70;
property bool checked
property QtObject temp: objRoot.name
color: checked ? "yellow" : "black" // (1)
//color: objRect.temp && objRect.temp.boolVal ? "yellow" : "black" //--->WORKS (2)
//color: objRoot.name && objRoot.name.boolVal ? "yellow" : "black" //--->DOES NOT WORK !!! (3)
Binding on checked {
//value: objRect.temp && objRect.temp.boolVal //--->DOES NOT WORK !!! (1a)
//value: objRect.temp !== null && objRect.temp.boolVal //--->WORKS (1b)
value: objRect.temp ? objRect.temp.boolVal : false //--->WORKS (1c)
//Using directly without collecting in local QtQobject temp:
//----------------------------------------------------------
//value: objRoot.name && objRoot.name.boolVal //--->DOES NOT WORK !!! (1d)
//value: objRoot.name !== null && objRoot.name.boolVal //--->DOES NOT WORK !!! (1e)
//value: objRoot.name ? objRoot.name.boolVal : false //--->DOES NOT WORK !!! (1f)
}
Text {
text: "Destroy"
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: objRoot.deleteName()
}
}
}
using: {Qt/QML 5.2.0, Win 7, MinGW 4.8, QtQuick 2.0}
Your property declaration looks strange to me: name can obviously change, but you've declared it CONSTANT. My guess is it it'd work a whole lot better without the CONSTANT, and instead provide a NOTIFY of a nameChanged signal emitted when the value of name changes, else there's no guarantee the QML states bound to the C++ properties will be updated.

Qt 5.2 QObject::connect: Cannot connect (null)::

I'm a noob - not good with QML or C++ yet, but getting there. I seem to have hit a stumbling block I can't get past. I'm receiving the following error in my attempt to run a build and I'm not sure what I missed in my code...
**QObject::connect: Cannot connect (null)::buttonClicked_enable() to TLA_Funcs::sys_enable()
**
I've looked through the other versions of the question here and it seems that I have my code correct, but I still get the error. Can someone take a peek? Here's the relevant sample of my code (the rest is too long and I left out the guts of the function - too long).
QML Code:
Rectangle {
id: main
width: 800
height: 600
color: "#abcfe9"
border.width: 4
border.color: "#000000"
signal buttonClicked_enable()
Button {
id: enable
x: 628
y: 55
text: "ENABLE"
onClicked:buttonClicked_enable()
}
//....
}
My class header:
#ifndef TLA_FUNCS_H
#define TLA_FUNCS_H
#include <QObject>
class TLA_Funcs : public QObject
{
Q_OBJECT
public:
explicit TLA_Funcs(QObject *parent = 0);
signals:
public slots:
Q_INVOKABLE void sys_enable(){return ;}
private:
};
#endif
And in my main.cpp file:
#include "TLA_Funcs.h"
TLA_Funcs::TLA_Funcs(QObject *parent) :
QObject(parent)
{
}
int main (int argc, char*argv[]) {
QGuiApplication app(argc, argv);
QQuickView *view = new QQuickView(QUrl("main.qml"));
view->show();
QQuickItem *item = view->rootObject();
TLA_Funcs *funcs = new TLA_Funcs();
QObject::connect(item, SIGNAL(buttonClicked_enable()), funcs, SLOT(sys_enable()));
}
I've defined the signals in the parent rectangle, and in the button code I've tried using:
onClicked:main.buttonClicked_enable()
as well as:
onClicked: {
buttonClicked_enable()
TLA_Funcs.sys_enable()
}
That didn't help either. I also tried defining the functions under "signal" in the class, but that made more of a mess. Can someone at least point me in the right direction, and keep in mind, I'm still a noob... Thanks All!!!
Problem Solved: there was an error in the .pro file. I copied the code into a new project and it worked correctly 100%. Thanks all for the help!