How should qml plugin c++ use singleton? - qt

I have created Qt Quick 2Extension Plugin in the name of MyTestPlugin
, inside I have created c++ file in the name of MySingleton, added QML_SINGLETON with in MySingleton class.
MySingleton.hpp
#ifndef TESTSINGLETON_H
#define TESTSINGLETON_H
#include <QQuickItem>
class TestSingleton : public QQuickItem
{
Q_OBJECT
Q_DISABLE_COPY(TestSingleton)
QML_SINGLETON
public:
explicit TestSingleton(QQuickItem *parent = nullptr);
~TestSingleton() override;
signals:
void testSignal();
public:
Q_INVOKABLE int testMethod();
};
#endif // MUSEAGORA_H
Then added codes below in MyTestPlugin.cpp
void MyTestPlugin::registerTypes(const char *uri)
{
// #uri TestSingleton
qmlRegisterSingletonInstance<TestSingleton>(uri, 1, 0, "TestSingleton", new TestSingleton());
}
Use qmlplugindump to create plugins.qmltypes:
import QtQuick.tooling 1.2
Module {
dependencies: [
"QtGraphicalEffects 1.12",
"QtQml 2.14",
"QtQml.Models 2.2",
"QtQuick 2.9",
"QtQuick.Controls 1.5",
"QtQuick.Controls.Styles 1.4",
"QtQuick.Extras 1.4",
"QtQuick.Layouts 1.1",
"QtQuick.Window 2.2"
]
Component {
name: "TestSingleton"
defaultProperty: "data"
prototype: "QQuickItem"
exports: ["MyTestPlugin/TestSingleton 1.0"]
isCreatable: false
isSingleton: true
exportMetaObjectRevisions: [0]
Signal { name: "testSignal" }
Method { name: "testMethod"; type: "int" }
}
}
Create a new project in qml import MyTestPlugin 1.0 and call MyTestPlugin.testMethod()
output Aas below
<Unknown File>: Registered object must live in the same thread as the engine it was registered with
<Unknown File>: qmlRegisterSingletonType(): "TestSingleton" is not available because the callback function returns a null pointer.
qrc:/main.qml:285: TypeError: Property 'testMethod' of object [object Object] is not a function
Can plugin use C++ singleton?
how should i use correctly?

I found the way by myself
static QObject *test_singleton_type_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
TestSingleton *e = new TestSingleton();
return e;
}
void MuseAgoraPlugin::registerTypes(const char *uri)
{
// #uri TestSingleton
qmlRegisterSingletonType< TestSingleton >(uri, 1, 0, "TestSingleton", test_singleton_type_provider);
}

Related

My custom QML gives error: "Cannot assign to non-existent property"

Here is my .h file:
#ifndef FDR_TCPSOCKET_H
#define FDR_TCPSOCKET_H
#include <QObject>
#include <QTcpSocket>
class FDR_TCPSocket : public QObject{
Q_OBJECT
public:
QTcpSocket* _socket;
FDR_TCPSocket(QObject* parent = Q_NULLPTR){
// Create the socket object.
_socket = new QTcpSocket(parent);
// Add events to the socket.
addEvents();
}
void addEvents(){
_socket->connect(_socket, &QTcpSocket::connected, [=]{
emit Connected();
});
}
signals:
void Connected();
public slots:
// ...
};
#endif // FDR_TCPSOCKET_H
And here is my QML:
import com.fedartech.qmlsockets 1.0
...
FDR_TCPSocket{
onConnected: { ... } <<<========== GIVES ERROR
}
But it gives this error:
Cannot assign to non-existent property "onConnected"
(BTW here is the register:)
qmlRegisterType<FDR_TCPSocket>("com.fedartech.qmlsockets", 1, 0, "FDR_TCPSocket");
Why is this happening? I really don't know.
Thanks for your helps!
Oh my god... Simple answer.
I changed the Connected() signal to the connected(). (first letter lowercased)
Now it works...

Using c++ enum in qml

I have an enum that I use in qml
class SettingManager : public QObject
{
Q_OBJECT
public:
enum BookKinds{
BookKind1=0,
BookKind2=1,
};
Q_ENUMS(BookKinds)
Q_PROPERTY(BookKinds bookKind READ bookKind WRITE setBookKind NOTIFY bookKindChanged)
explicit SettingManager(QObject *parent = nullptr);
void setBookKind(BookKinds dkob);
BookKinds bookKind();
signals:
void bookKindChanged();
};
in main.cpp I registerd SettingManager
qmlRegisterType<SettingManager>("Test",1,0,"SettingManager");
I use this in qml file
onCurrentIndexChanged:
{
if(tbarBookKindForDisplay.currentIndex==0)
{
settingManager.bookKind=BookManager.BookKind1;
}
else if(tbarBookKindForDisplay.currentIndex==1){
settingManager.bookKind=BookManager.BookKind2;
}
}
when CurrentIndex of TabBar changes below error occurs:
Error: Cannot assign [undefined] to int
You register the type as SettingManager but use it as BookManager. The correct code is:
settingManager.bookKind = SettingManager.BookKind1;
You should also use Q_ENUM instead of Q_ENUMS.

How to detect dataChanged() and resourcesChanged() from QML

The codes below:
Item{
onDataChanged: console.log("Data changed")
}
Item{
onResourcesChanged: console.log("Resources changed")
}
throw Cannot assign to non-existent property "onDataChanged" and Cannot assign to non-existent property "onResourcesChanged" respectively.
This is not the case with the childrenChanged() signal. The reason for this is that in qtdeclarative/src/quick/items/qquickitem.h, children property is declared with:
Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQmlListProperty<QQuickItem> children READ children NOTIFY childrenChanged DESIGNABLE false)
but this is not the case for data or resources. They are declared with:
Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQmlListProperty<QObject> data READ data DESIGNABLE false)
Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQmlListProperty<QObject> resources READ resources DESIGNABLE false)
with no changed() signal. Why is this design choice to particularly hide the change on non-visible children made? Moreover, how can the change on data be detected from QML?
Why do you need this ?
One possible workaround is to listen for child events. I wrote a quick attached type PoC :
ChildListener.h :
#ifndef CHILDLISTENER_H
#define CHILDLISTENER_H
#include <QObject>
#include <QtQml>
class ChildListener : public QObject {
Q_OBJECT
public:
ChildListener(QObject *object) : QObject(object) {
if (object)
object->installEventFilter(this);
}
static ChildListener *qmlAttachedProperties(QObject *object) {
return new ChildListener(object);
}
signals:
void childAdded(QObject* child);
void childRemoved(QObject* child);
protected:
bool eventFilter(QObject *obj, QEvent *event) override {
Q_UNUSED(obj)
if (QChildEvent *childEvent = dynamic_cast<QChildEvent*>(event)) {
if (childEvent->added())
emit childAdded(childEvent->child());
if (childEvent->removed())
emit childRemoved(childEvent->child());
}
return false;
}
};
QML_DECLARE_TYPEINFO(ChildListener, QML_HAS_ATTACHED_PROPERTIES)
#endif // CHILDLISTENER_H
Register it with qmlRegisterUncreatableType<ChildListener>("fr.grecko.ChildListener", 1, 0, "ChildListener", "ChildListener can only be accessed as an attached type."); and you can now use it like so :
import fr.grecko.ChildListener 1.0
/* ... */
Timer {
id: foo
objectName: "My name is foo"
}
Item {
ChildListener.onChildAdded: print("child added : ", child)
data: [foo];
}
This outputs : qml: child added : QQmlTimer(0x7ffe22f538e0, "My name is foo") in the console

How to store global data in QList

Can you explain a methods for storing program data with global access ?
I found these keywords:
- using static class to store data
- pass QList by value
- pass Qlist by reference
- use 'friend' keyword
but I cannot find any real example of storing global QList, as they say, it is a bad design to use global variables. Also there is a mention that using pointers on a QList is a bad idea because of implicit sharing (?).
So where should I store my Qlist for accessing it from a different class in an other .cpp ? So I have:
mainwindow.h
QList <SceneCard> sceneList;
QString mTitle;
public slots:
QString setValue()
{
return mTitle;
}
mainwindow.cpp
MainWindow::AddScene()
{
sceneCard = new SceneCard(sNumber);
sceneList.append(sceneCard);
mTitle = "Nejat is right!"
}
void MainWindow::showSceneCard()
{
SceneDialog D;
connect(D,SIGNAL(getValue()),this,SLOT(setValue()));
D.exec();
}
scenedialog.h
#ifndef SCENEDIALOG_H
#define SCENEDIALOG_H
#include <QDialog>
#include <QList>
namespace Ui {
class SceneDialog;
}
class SceneDialog : public QDialog
{
Q_OBJECT
public:
SceneDialog(QWidget *parent = 0);
~SceneDialog();
signals:
QString getValue();
private:
Ui::SceneDialog *ui;
QString myText;
};
scenedialog.cpp
#include "scenedialog.h"
#include "ui_scenedialog.h"
#include <QDebug>
SceneDialog::SceneDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::SceneDialog)
{
ui->setupUi(this);
myText = getValue();
qDebug() << myText; // myText is empty!!
}
You can put your list as a class member and use Qt's Signal/slot mechanism to access the list from other classes. Just make a signal in the target class, connect it to a slot in the class containing the list and make a connection between two objects of the classes. This way you can access any data member of other classes by connecting a signal to a slot returning that value and just emitting the signal and getting the return value.
For example if you have two classes like :
class A: public QObject
{
Q_OBJECT
public:
A(QObject *parent = 0);
~A();
signals:
int getValue();
private:
void someFunction()
{
int val = getValue();
}
};
class B
{
Q_OBJECT
public:
B(QObject *parent = 0);
~B();
public slots:
int getValue()
{
return someValue;
}
};
And connect the signal from an object of A to the slot in an object of B :
connect(a, SIGNAL(getValue()), b, SLOT(getValue()));
In class A you can access the value returned from getValue slot in B by just calling the signal and using the returned value.
Note that the two objects should be in the same thread for this to work. If they are in different threads then the connection type should be of type Qt::BlockingQueuedConnection :
connect(a, SIGNAL(getValue()), b, SLOT(getValue()), Qt::BlockingQueuedConnection);
Another way is two use static class members but it is not recommended unless you have a good reason to do it. If you have two classes like :
class A {
public:
static QList<int> list;
};
class B {
public:
void do_something();
};
You can access A's static data member from B like this:
void B::do_something()
{
int val = A::list[0];
...
};

C++ method defined in .h called in .cpp is not recognized

I am trying to use a method called getName() that is defined in the addPlayer.h file below. The getname() method will be used in the constructor called Player. The error that I get is: 'getName' was not declared in this scope'. How can I fix it?
Thanks for helping.
The addPlayer.h file:
#include "../Source/Player.h"
class addPlayer : public QDialog
{
Q_OBJECT
public:
addPlayer(QWidget *parent = 0);
~addPlayer();
tp::Player* makePlayer();
void addPlayer();
QString getName() const;
inline QString addPlayer::getName() const
{
return (ui.name_lineEdit->text());
}
The addPlayer.cpp file:
#include "addPlayer.h"
#include <QMessageBox>
using namespace tp;
addPlayer::addPlayer(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
QObject::connect(ui.ok_pushButton, SIGNAL(clicked()), this,
SLOT(validatePlayer()));
QObject::connect(ui.dateNaissance_pushButton, SIGNAL(clicked()), this,
SLOT(getDate()));
}
addPlayer::~addPlayer()
{
}
Player* makePlayer()
{
return new Player(getName().toStdString());
}
The constructor is as follows:
class Player: public HumanBeing {
public:
//Constructor
Player(const std::string& p_name);
Player::Player(const std::string& p_name): m_name(p_name)
You haven't properly scoped your definition of makePlayer -- you need to prefix addPlayer:::
Player* addPlayer::makePlayer()
{
return new Player(getName().toStdString());
}

Resources