PDA

View Full Version : Can't get the notify signal in QML



iveus
7th February 2020, 18:05
Hi. I have a problem.
For some reason, the Q_PROPERTY NOTIFY does not work in QML. I do understand, that i'm missing something, but don't get what for a 3rd day ;)

1. I have two classes, one is BoardWiring, second is MainUi.
2. In MainUi - i have one integer, called minTimer, with the NOTIFY onMinTimerChanged().
3. The classes BoardWiring and MainUi are added in main.cpp, to use in QML.
4. The MainUi is added in private section of BoardWiring.
5. Then, I call BoardWiring.start() from QML, which calls MainUi.startTimer(), which suppose to change the static MainUi.minTimer integer to 1.
5. The MainUi.minTimer is changed, but i can't receive the NOTIFY signal in QML, it's just not notified minTimerElement.

Can someone help me with this please?


Here's the minimum of the code to reproduce:

main.cpp



#include <QDebug>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QQuickView>
#include <QSettings>

#include "boardwiring.h"
#include "mainui.h"
#include <QString>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {

QCoreApplication::setAttribute(Qt::AA_EnableHighDp iScaling);
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLC ontexts);

QGuiApplication app(argc, argv);

QtWebEngine::initialize();

QCoreApplication::setOrganizationName("Test");
QCoreApplication::setOrganizationDomain("Test");
QCoreApplication::setApplicationName("Test");

// qmlRegisterType<BoardWiring>("io.qt.boardwiring", 1, 0, "BoardWiring");
// qmlRegisterType<MainUi>("io.qt.mainui", 1, 0, "MainUi");

BoardWiring boardwiring;
MainUi mainui;

QQmlApplicationEngine engine;

engine.rootContext()->setContextProperty("boardwiring", &boardwiring);
engine.rootContext()->setContextProperty("mainui", &mainui);

engine.load(QUrl(QStringLiteral("qrc:/Main.qml")));

return app.exec();

}


Main.qml



import QtQuick 2.12
import QtQuick.Controls 2.9
import QtQuick.Controls.Imagine 2.4
import QtQuick.Window 2.3

ApplicationWindow {
id: window
visible: true
width: 1280
height: 600
title: qsTr("Test")

RoundButton {
id: startButton
x: 14
y: 26
width: 230
height: 230
text: !boardwiring.isStarted ? "Start" : "Stop"
font.pointSize: 30
background: Image { source: boardwiring.isStarted? "/stop.png" : "/Start.png"; }
onClicked: {
if(!boardwiring.isStarted) {
boardwiring.start();
console.log("Main ui: " + mainui.minTimer);
} else {
boardwiring.stop();
console.log("Main ui: " + mainui.minTimer);
}

}

contentItem: Text {
text: startButton.text
font: startButton.font
opacity: 1.0
color: "black"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}

Text {
id: minTimerElement
x: 979
y: 291
text: mainui.minTimer // Not notifies it!
font.pixelSize: 16
}


}



boardwiring.h


#ifndef BOARDWIRING_H
#define BOARDWIRING_H

#include "mainui.h"
#include <QObject>
#include <QString>

class BoardWiring : public QObject {
Q_OBJECT

Q_PROPERTY(bool isStarted READ isStarted NOTIFY isStartedChanged WRITE
setIsStarted)

public:
explicit BoardWiring(QObject *parent = nullptr);

bool isStarted();

Q_INVOKABLE void start();
Q_INVOKABLE void setIsStarted(bool &isStarted);


signals:
void isStartedChanged(bool b_isStarted);


public slots:


private:
MainUi mainUi;
static bool b_isStarted;
};

#endif // BOARDWIRING_H



boardwiring.cpp



#include "boardwiring.h"
#include <QDebug>
#include <QString>

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

bool BoardWiring::b_isStarted = 0;

bool BoardWiring::isStarted() { return b_isStarted; }
void BoardWiring::setIsStarted(bool &isStarted) {
b_isStarted = isStarted;
emit isStartedChanged(isStarted);
}

BoardWiring::BoardWiring(QObject *parent) : QObject(parent) {}

void BoardWiring::start() {


if (!b_isStarted) {
qDebug() << "STARTED";
b_isStarted = true;

mainUi.startTimer(); // Here i call the startTimer
}

emit isStartedChanged(b_isStarted);
}


void BoardWiring::stop() {

b_isStarted = false;

mainUi.stopTimer();

emit isStartedChanged(b_isStarted);

}



mainui.h


#ifndef MAINUI_H
#define MAINUI_H

#include <QObject>
#include <QString>

class MainUi : public QObject {
Q_OBJECT

Q_PROPERTY(
int minTimer READ minTimer NOTIFY minTimerChanged WRITE setMinTimer)

public:
explicit MainUi(QObject *parent = nullptr);

Q_INVOKABLE void startTimer();

int minTimer();

signals:
void minTimerChanged(const int &m_minTimer);

public slots:
void stopTimer();
void setMinTimer(int &minTimer);


private:
static int m_minTimer;
};

#endif // MAINUI_H



mainui.cpp


#include "mainui.h"
#include <QDebug>
#include <QSettings>
#include <QTimer>

int MainUi::m_minTimer = 0;

MainUi::MainUi(QObject *parent) : QObject(parent) {}

int MainUi::minTimer() { return m_minTimer; }
void MainUi::setMinTimer(int &minTimer) {
m_minTimer = minTimer;
emit minTimerChanged(minTimer);
}

void MainUi::startTimer() {
m_minTimer = 1;
setMinTimer(m_minTimer);

}

void MainUi::stopTimer() {
m_minTimer = 0;
setMinTimer(m_minTimer);
}

ChrisW67
7th February 2020, 23:02
The mainui object you expose to QML is declared at main.cpp line 32. This is the object you are accessing as mainui on the QML side.

boardwiring.h line 32 creates a member variable mainui. This is the object you call startTimer() on in BoardWiring::start() and the object that should be emitting a signal.

iveus
8th February 2020, 11:43
The mainui object you expose to QML is declared at main.cpp line 32. This is the object you are accessing as mainui on the QML side.

boardwiring.h line 32 creates a member variable mainui. This is the object you call startTimer() on in BoardWiring::start() and the object that should be emitting a signal.

Thank you! I can put an timer on QML, so it will read this value, but, what will be the best way to restructure the code, in order to notify from other object?

Second, for example, if i wan't to call MainUi::stopBoardAndTimer(), which will call BoardWiring::stop(); I suspect, this will also not notify the change isStarted to QML, that was in BoardWiring class. Is there any possibility to connect all between each other?