Solved Registering an Instantiable Object Type
-
Hi,
Im trying to Register an Instantiable Object just like in this official example
But when i create the object QML side, my properties are not assigned//my class simplified (i keep only one property) class PlcCom : public QObject { Q_OBJECT Q_PROPERTY(int port READ port WRITE setPort NOTIFY portChanged) public: explicit PlcCom(QObject *parent = nullptr); int port() const { return m_port; } void setPort(int port) { if (m_port == port) return; m_port = port; emit portChanged(m_port); } //... private : int m_port = 0; QString hostAdr = "127.0.0.1"; ... //main.cpp qmlRegisterType<PlcCom>("com.not.testComApi", 1, 0, "PlcCom"); //qml import com.not.testComApi 1.0 Window { PlcCom{ id:p2 port:62944 hostAdr: "10.81.4.108" request : "myRequest" Component.onCompleted: { // i also tryed //p2.hostAdr = "10.81.4.108" //p2.port = 62944 //request = "myRequest" } }
the problem is my object is created with default property values, this line in PlcCom ctor
qDebug()<<"connecting : " << m_hostAdr << ":"<<m_port;
will output :
connecting : "127.0.0.1" : 0 but i expect 10.81.4.108:62944
Can someone tell me what i'm missing please ?
-
hi @LeLev
IIRC your setPort function has to be markt as slot
public slots: void setPort(int port) { if (m_port == port) return; m_port = port; emit portChanged(m_port); }
I think the QML-CPP communication requires Q_OBJECT macro and proper slot macros to work correctly.
-
Thank you
@J.Hilk said in Registering an Instantiable Object Type:has to be markt as slot
now it is but still not initialized correctly
-
@LeLev mmh,
do you initialize the QObject parent correctly? -
@J.Hilk please see the full class code
class PlcCom : public QObject { Q_OBJECT Q_PROPERTY(QString request READ request WRITE setRequest NOTIFY requestChanged) Q_PROPERTY(QString stringValue READ stringValue WRITE setStringValue NOTIFY stringValueChanged) Q_PROPERTY(QString hostAdr READ hostAdr WRITE setHostAdr NOTIFY hostAdrChanged) Q_PROPERTY(int port READ port WRITE setPort NOTIFY portChanged) public: explicit PlcCom(QObject *parent = nullptr); public slots: QString request() const {return m_request;} void setRequest(QString request) { if (m_request == request) return; m_request = request; emit requestChanged(m_request); } QString stringValue() const{return m_stringValue;} void setStringValue(QString stringValue) { m_stringValue = stringValue; emit stringValueChanged(m_stringValue); } QString hostAdr() const{ return m_hostAdr;} void setHostAdr(QString hostAdr) { if (m_hostAdr == hostAdr) return; m_hostAdr = hostAdr; emit hostAdrChanged(m_hostAdr); } int port() const{return m_port;} void setPort(int port) { if (m_port == port) return; m_port = port; emit portChanged(m_port); } signals: void requestChanged(QString request); void stringValueChanged(QString stringValue); void hostAdrChanged(QString hostAdr); void portChanged(int port); private : void socketConnected(); void socketDisconnected(); void responseReady(); private: QString m_request; QString m_stringValue; QString m_hostAdr; int m_port; QTcpSocket *sk; };
PlcCom::PlcCom(QObject *parent) : QObject(parent) { sk = new QTcpSocket(this); QObject::connect(sk,&QTcpSocket::connected,this,&PlcCom::socketConnected); QObject::connect(sk,&QTcpSocket::disconnected,this,&PlcCom::socketDisconnected); QObject::connect(sk,&QTcpSocket::readyRead,this,&PlcCom::responseReady); connect(sk, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), [=](QAbstractSocket::SocketError err){ qDebug()<<"SocketError"; }); //qDebug()<<"connecting : " << m_hostAdr << ":"<<m_port; // here output default values // BADFIX : TODO improve , QML properties not set directly ? QObject::connect(this,&PlcCom::hostAdrChanged,[&](){ // here everything is initialized with qml values qDebug()<<"connecting : " << m_hostAdr << ":"<<m_port; sk->connectToHost(QHostAddress(m_hostAdr),static_cast<quint16>(m_port)); if(!sk->waitForConnected(5000)) { qDebug() << "Error: " << sk->errorString(); return; } }); } void PlcCom::socketConnected() { qDebug("CONNECTED."); QString c = m_request; qDebug()<<"SENDING COMMAND : " << c; c.append("\n"); sk->write(c.toLatin1(),c.length()); } void PlcCom::socketDisconnected() { qDebug("DISCONNECTED..."); } void PlcCom::responseReady() { qDebug() << "reading..."; setStringValue(sk->readAll()); }
-
@LeLev
I can't reproduce this,
take this minimal example:#ifndef MYCLASS_H #define MYCLASS_H #include <QObject> #include <QDebug> class myClass : public QObject { Q_OBJECT Q_PROPERTY(QString hostAdr READ hostAdr WRITE setHostAdr NOTIFY hostAdrChanged) public: explicit myClass(QObject *parent = nullptr) :QObject(parent) { connect(this, &myClass::hostAdrChanged, this, [](QString hostAdr)->void{ qDebug() <<hostAdr; }); } const QString &hostAdr() const { return m_hostAdr; } signals: void hostAdrChanged(const QString &hostAdr); public slots: void setHostAdr(const QString &hostAdr) { if (m_hostAdr == hostAdr) return; m_hostAdr = hostAdr; emit hostAdrChanged(m_hostAdr); } private: QString m_hostAdr; }; #endif // MYCLASS_H
//main.cpp int main(int argc, char *argv[]) { QApplication app(argc, argv); qmlRegisterType<myClass>("com.not.testComApi", 1, 0, "PlcCom"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; }
import QtQuick 2.12 import QtQuick.Controls 2.5 import com.not.testComApi 1.0 ApplicationWindow { visible:true width:500; height:500 PlcCom{ hostAdr: "abcd" } }
the changed signal is emitted fine with the correct string
-
@J.Hilk thank you very much.
I did the same way (see my previous post), only i wonder why i have to handle that hostAdrChanged signal ? i want to create the object directly with right parameter values, QML side.In my constructor
qDebug()<<"connecting : " << m_hostAdr << ":"<<m_port;
this will output default values,
but if i doQObject::connect(this,&PlcCom::hostAdrChanged,[&](){ qDebug()<<"connecting : " << m_hostAdr << ":"<<m_port;
here everything is initialized with qml values
-
@LeLev
well the c++ part is initialized first. You class gets initiated -> call of the constructorthen it's passed to the qml engine, then the values from there are taken and set.
if you want to initialize your values from qml side only, you can do that to.
IIRC there is QQmlParserStatus Class
When your class inherits from that as well as from QObject you can override the virtual
componentComplete
function and do your initialization there.That one is called together with the QML
Component.onCompleted: ...
signal -
@J.Hilk Yes thank you again! i was reading this also : https://doc.qt.io/qt-5/qtqml-cppintegration-definetypes.html#receiving-notifications-for-object-initialization