Qt Signals and Slots - nothing happens - c++

I'm currently trying to connect a QML Signal to a C++ Slot unsuccessfully.
I just had a look on several other examples but I think i didn't got it with how to get the root object of a qml document...
My problem is, it seems like the signal will be sent from the qml file, but not received in the cpp file. There are no errors when I execute this code.
//Counter.h
#ifndef COUNTER_H
#define COUNTER_H
#include <QObject>
class Counter : public QObject
{
Q_OBJECT
private:
int counter;
public:
explicit Counter(QObject *parent = 0);
signals:
void counterHasChanged(int);
public slots:
void click();
};
#endif // COUNTER_H
//counter.cpp
#include "counter.h"
#include <QDebug>
Counter::Counter(QObject *parent) :
QObject(parent)
{
this->counter = 0;
qDebug() << "Class Counter created";
}
void Counter::click() {
this->counter++;
qDebug() << "clickRegistered() - emit counterHasChanged()";
emit counterHasChanged(counter);
}
//main.cpp
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include "counter.h"
#include <QObject>
#include <QtQuick>
#include <QDebug>
#include <QQuickItem>
#include <QQmlContext>
#include <QtCore>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QtQuick2ApplicationViewer viewer;
viewer.setMainQmlFile(QStringLiteral("qml/StatesTest2/main.qml"));
viewer.showExpanded();
QQuickView view;
view.setSource(QUrl::fromLocalFile("qml/StatesTest2/main.qml"));
QObject *item = view.rootObject();
Counter counter;
QObject::connect(item, SIGNAL(click()), &counter, SLOT(click()));
return app.exec();
}
//main.qml
import QtQuick 2.0
Rectangle {
id: root
width: 360
height: 360
signal click
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
root.click
console.log("click() qml")
}
}
Text {
text: "clicks: "
x: 30
y: 250
}
Text {
id: counter
text: "0"
x: 75
y: 250
}
}
I know there are tons of topics like this..
For some reason, no other solution worked for me.. maybe I should change my IDE :D

I suggest you to add counter as a context property.. This requires following changes.
//Counter.h
#ifndef COUNTER_H
#define COUNTER_H
#include <QObject>
class Counter : public QObject
{
Q_OBJECT
private:
int counter;
public:
explicit Counter(QObject *parent = 0);
signals:
void counterHasChanged(int Value);
public slots:
void click();
};
#endif // COUNTER_H
The Counter.cpp file
//counter.cpp
#include "counter.h"
#include <QDebug>
Counter::Counter(QObject *parent) :
QObject(parent)
{
this->counter = 0;
qDebug() << "Class Counter created";
}
void Counter::click() {
this->counter++;
qDebug() << "clickRegistered() - emit counterHasChanged()";
emit counterHasChanged(counter);
}
The main.cpp file
//main.cpp
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include "counter.h"
#include <QObject>
#include <QtQuick>
#include <QDebug>
#include <QQuickItem>
#include <QQmlContext>
#include <QtCore>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
Counter counter;
QtQuick2ApplicationViewer viewer;
viewer.rootContext()->setContextProperty("counterObj",&counter);
viewer.setMainQmlFile(QStringLiteral("qml/SO_QMLCPPCommunication/main.qml"));
viewer.showExpanded();
return app.exec();
}
And in the qml file, you can access the slot of the Counter object by referring to counterObj.
//main.qml
import QtQuick 2.0
Rectangle {
id: root
width: 360
height: 360
signal click
Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
counterObj.click()
console.log("click() qml")
}
}
Text {
text: "clicks: "
x: 30
y: 250
}
Text {
id: counter
text: "0"
x: 75
y: 250
}
Connections
{
id:cppConnection
target:counterObj
ignoreUnknownSignals : true
onCounterHasChanged:{
//To access signal parameter,please name the parameter.
console.debug("Counter value changed")
counter.text = Value
}
}
}

QQuickView::rootObject() returns you a QQuickItem which apparently on Qt5.0 hasn't any click signal (http://qt-project.org/doc/qt-5.0/qtquick/qquickitem.html)
Make sure you're linking the right (existing) signal to the right slot and that the signal gets actually called.

Related

Not able to push a value from Qt to QML

I am trying to read a value from mysql db through Qt and push the value to QML(specifically to a CircularGauge dial). I am successfully able to read the db value and print it to console in Qt. When I try to expose the value to QML, it is not getting reflected in QML dashboard. The following are my files:-
qml.h
#ifndef QML_H
#define QML_H
#include <QObject>
#include <QVariant>
#include <QDebug>
#include <QTime>
#include <qquickimageprovider.h>
#include <QImage>
#include <QString>
/*------------------------------SPEED------------------------------*/
class Speed : public QObject
{
Q_OBJECT
Q_PROPERTY(double velocity MEMBER m_velocity NOTIFY velocityChanged)
public:
Speed(QObject* parent = nullptr);
virtual ~Speed() {}
const double MPS2KNOTS = 1.94;
void velocityCallback();
private slots:
void updateVelocity(double x);
signals:
void velocityChanged();
void receivedVelocity(double x);
private:
double m_velocity = 0.0;
};
#endif // QML_H
qml.cpp
#include <QSqlDatabase>
#include <QSqlQueryModel>
#include <QSqlQuery>
#include <QDebug>
#include <qml.h>
Speed::Speed(QObject*)
{
connect(this, SIGNAL(receivedVelocity(double)), this, SLOT(updateVelocity(double)));
}
void Speed::velocityCallback()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("localhost");
db.setDatabaseName("sim_speed");
db.setUserName("administrator");
db.setPassword("test");
bool ok = db.open();
double x;
QSqlQuery query;
//while (ok) {
query.prepare("SELECT speed FROM speed");
query.exec();
if (query.next()) {
x= query.value(0).toDouble();
}
qDebug() << "Value is";
qDebug() << ok;
qDebug() << x;
receivedVelocity(x);
//}
}
void Speed::updateVelocity(double x)
{
m_velocity = x;
emit velocityChanged();
qDebug() << m_velocity;
}
main.cpp
#include <functional>
#include <QCoreApplication>
#include <QObject>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QUrl>
#include <QString>
#include <QQuickWindow>
#include <QtQml>
#include <QtConcurrent/QtConcurrent>
#include <QFuture>
#include <QFutureWatcher>
#include <qml.h>
#include <QQmlProperty>
#include <thread> // std::thread
#include <QDebug>
#include <QCoreApplication>
#include <QTextStream>
#include <QFile>
using namespace std;
int main(int argc, char** argv)
{
//std::thread dbret(velocityCallback());
QGuiApplication app(argc, argv);
Speed speedqml(&app);
//QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){});
QQmlApplicationEngine engine(&app);
engine.rootContext()->setContextProperty("velocity", &speedqml);
Speed sp;
sp.velocityCallback();
engine.load(QUrl("qrc:/main.qml"));
// std::thread dbret(mainn);
//dbret.join();
return app.exec();
}
main.qml
import QtMultimedia 5.8
import QtQuick 2.2
import QtQuick.Window 2.1
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Extras 1.4
import QtSensors 5.10
//import Ros 1.0
Window {
visible: true
width: 1920
height: 1080
title: qsTr("Gazebo")
Rectangle {
id: speedometer
x: 10
y: 10
width: 150
height:150
radius: width*0.5
opacity: 0.5
color: "black"
CircularGauge {
id:gauge
value: velocity.velocity
maximumValue : 10
x:10
y:10
width:150
height:150
anchors.centerIn: parent
style: CircularGaugeStyle {
labelStepSize: 0.5
tickmarkStepSize: 0.5
}
Text {
text: "Speed:"+velocity.velocity+"m/s"
anchors.top:parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
}
Behavior on value {
NumberAnimation {
duration: 1000
}
}
MouseArea {
anchors.fill: parent
onClicked: {
// tachometer.visible = false
// speedometer.visible = false
// compassdial.visible = false
// altimeterback.visible = false
// ammeter.visible = false
// voltmeter.visible = false
// throttlegauge.visible = false
// dashboard.visible = true
}
}
}
}
}

How to call QTimer from other class n Qt C++? [duplicate]

This question already has answers here:
C++ variable scope
(2 answers)
Closed 3 years ago.
I am using an QML in Qt.
Having two classes,
Board class and TimerUi class.
QML calls the Board::start()
The Board::start() calls the TimerUi::startTimer().
The problem is, QTimer in TimerUi class does not start at all. The main thing i wanted, is to leave all timer based functions in one place, and have ability to call it from any class.
If i call the TimerUi::startTimer() directly from QML - it works.
Can someone explain me please, where is my error?
main.cpp
#include <QDebug>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QSettings>
#include <QString>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "board.h"
int main(int argc, char *argv[]) {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
QGuiApplication app(argc, argv);
QCoreApplication::setOrganizationName("Test");
QCoreApplication::setOrganizationDomain("test");
QCoreApplication::setApplicationName("Test");
qmlRegisterType<Board>("io.qt.board", 1, 0, "Board");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/Main.qml")));
return app.exec();
}
Main.qml
import QtQuick 2.12
import QtQuick.Controls 2.9
import io.qt.board 1.0
import QtQuick.Controls.Imagine 2.4
import QtQuick.Window 2.3
import QtWebEngine 1.0
ApplicationWindow {
id: window
visible: true
width: 800
height: 600
title: qsTr("Stack")
// Init Board
Board {id: board}
// Init
Component.onCompleted: {
board.init();
}
RoundButton {
id: startButton
x: 14
y: 26
width: 230
height: 230
text: !board.isStarted ? "Start" : "Stop"
font.pointSize: 30
background: Image { source: board.isStarted? "/stop.png" : "/start.png"; }
onClicked: board.start()
contentItem: Text {
text: startButton.text
font: startButton.font
opacity: enabled ? 1.0 : 0.3
color: "black"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
}
board.h
#ifndef BOARD_H
#define BOARD_H
#include <QObject>
#include <QString>
#include <QTimer>
class Board : public QObject {
Q_OBJECT
Q_PROPERTY(bool isStarted READ isStarted NOTIFY isStartedChanged WRITE
setIsStarted)
public:
explicit Board(QObject *parent = nullptr);
bool isStarted();
Q_INVOKABLE void init();
Q_INVOKABLE void start();
signals:
void isStartedChanged(bool b_isStarted);
public slots:
private:
QString b_start;
static bool b_isStarted;
};
#endif // BOARD_H
board.cpp
#include "board.h"
#include "timerui.h"
#include <QDebug>
#include <QString>
#include <QTimer>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
bool Board::b_isStarted = 0;
bool Board::isStarted() { return b_isStarted; }
void Board::setIsStarted(bool &isStarted) {
b_isStarted = isStarted;
emit isStartedChanged(isStarted);
}
Board::Board(QObject *parent) : QObject(parent) {}
void Board::init() {
qDebug() << "Some init";
}
// Start
void Board::start() {
TimerUi timerUi;
if (!b_isStarted) {
qDebug() << "isStarted";
b_isStarted = true;
timerUi.startTimer(); // <-- Here
}
emit isStartedChanged(b_isStarted);
}
timerui.h
#ifndef TIMERUI_H
#define TIMERUI_H
#include <QObject>
#include <QString>
#include <QTimer>
class TimerUi : public QObject {
Q_OBJECT
QTimer *m_timer;
Q_PROPERTY(int minTimer READ minTimer NOTIFY minTimerChanged())
public:
explicit TimerUi(QObject *parent = nullptr);
Q_INVOKABLE void startTimer(QObject *target);
int minTimer();
signals:
void minTimerChanged();
public slots:
void setTime();
private:
static int m_minTimer;
};
#endif // TIMERUI_H
timer.cpp
#include "timerui.h"
#include <QDebug>
#include <QSettings>
#include <QTimer>
int TimerUi::m_minTimer = 0;
TimerUi::TimerUi(QObject *parent) : QObject(parent) {}
int TimerUi::minTimer() { return m_minTimer; }
void TimerUi::startTimer() {
m_minTimer = 0;
// Timer
QTimer *m_timer = new QTimer(this);
connect(m_timer, SIGNAL(timeout()), this, SLOT(setTime()));
m_timer->start(1000);
}
void TimerUi::setTime() {
minTimer++;
qDebug() << "Hello " << minTimer;
emit minTimerChanged();
}
Thanks.
You declare your TimerUI in the local scope of Board::start, it is destroyed when the function end. That is probably where your problem come from.

How does setContextProperty() fail in this situation?

I have got three classes created in C++ as Window, PropertyList and MyParams and I want to pass PropertyList and MyParams these two classes to qml.
class Window
{
public:
PropertyList* getPropertyList();
private:
PropertyList* propertyList;
};
class PropertyList : public QObject
{
Q_OBJECT
public:
MyParams* getMyParams();
Q_INVOKABLE void test();
private:
MyParams* myParams;
};
class MyParams : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE void test();
};
int main(int argc, char *argv[])
{
Window* window = new Window();
PropertyList* propertyList = window->getPropertyList();
MyParams* myParam = propertyList->getMyParams();
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty(QStringLiteral("myParams"), myParam);
engine.rootContext()->setContextProperty(QStringLiteral("propertyList"), propertyList);
}
Why does this work:
engine.rootContext()->setContextProperty(QStringLiteral("propertyList"), propertyList);
And this fail:
engine.rootContext()->setContextProperty(QStringLiteral("myParams"), myParam);
Is it because I declare PropertyList as Q_OBJECT? And how can I fix this? Thanks a lot.
propertyList.test() can be called succesfully while myParams.test() cannot be called and crashed the qml.
I cannot see any problems in your code example, because the sample is not complete (Consider: https://stackoverflow.com/help/reprex).
Nevertheless I implemented a solution for you. I hope it will help. (Warning: there will be memory leaks around class Window, but it should helpt to understand C++ and Qml binding)
Here is your PropertyList.h:
#ifndef PROPERTYLIST_H
#define PROPERTYLIST_H
#include "myparams.h"
#include <QObject>
class PropertyList : public QObject
{
Q_OBJECT
public:
explicit PropertyList(QObject *parent = nullptr) : QObject (parent) { }
MyParams* getMyParams()
{
return myParams;
}
Q_INVOKABLE void test()
{
qDebug() << "PropertyList test";
}
private:
MyParams* myParams = new MyParams();
};
#endif // PROPERTYLIST_H
Here is your MyParams.h:
#ifndef MYPARAMS_H
#define MYPARAMS_H
#include <QObject>
#include <QDebug>
class MyParams : public QObject
{
Q_OBJECT
public:
explicit MyParams(QObject *parent = nullptr) : QObject (parent) { }
Q_INVOKABLE void test()
{
qDebug() << "MyParams test";
}
};
#endif // MYPARAMS_H
Here is your main.cpp:
#include "propertylist.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlEngine>
#include <QQmlContext>
#include <QDebug>
class Window
{
public:
PropertyList* getPropertyList()
{
return propertyList;
}
private:
PropertyList* propertyList = new PropertyList(nullptr);
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
Window* window = new Window();
PropertyList* propertyList = window->getPropertyList();
MyParams* myParam = propertyList->getMyParams();
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty(QStringLiteral("myParams"), myParam);
engine.rootContext()->setContextProperty(QStringLiteral("propertyList"), propertyList);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
{
return -1;
}
return app.exec();
}
Here is your main.qml:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ColumnLayout {
anchors.centerIn: parent
Button {
text: "myParams"
onClicked: {
myParams.test()
}
}
Button {
text: "propertyList"
onClicked: {
propertyList.test()
}
}
}
}

QT5 C++ Signal to QML Slot not working [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I know this question as been multiple times . I have browsed and trying for 5 days to link my C++ signal to a QML slot via Connections in QML . Here is my code at the moment and I don't understand why I always get :Cannot assign to non-existent property "ondashsetupChanged"
Please tell me what i am doing wrong ? The complete code is here :
https://github.com/BastianGschrey/PowerTune/tree/Simplification
Here is my code:
my main.cpp :
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QtQml>
#include "connect.h"
int main(int argc, char *argv[])
{
qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard"));
QApplication app(argc, argv);
app.setOrganizationName("Power-Tune");
app.setOrganizationDomain("power-tune.org");
app.setApplicationName("PowerTune");
QQmlApplicationEngine engine;
qmlRegisterType<Connect>("com.powertune", 1, 0, "ConnectObject");
engine.rootContext()->setContextProperty("Connect", new Connect(&engine));
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
connect.cpp :
#include "datalogger.h"
#include "connect.h"
#include "calculations.h"
#include "sensors.h"
#include "AdaptronicSelect.h"
#include "AdaptronicCAN.h"
#include "Apexi.h"
#include "HaltechCAN.h"
#include "Nissanconsult.h"
#include "obd.h"
#include "AdaptronicCAN.h"
#include "HaltechCAN.h"
#include "Apexi.h"
#include "AdaptronicSelect.h"
#include "dashboard.h"
#include "serialport.h"
#include "appsettings.h"
#include "gopro.h"
#include "gps.h"
#include <QDebug>
#include <QTime>
#include <QTimer>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QQmlContext>
#include <QQmlApplicationEngine>
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
#include <QByteArrayMatcher>
#include <QProcess>
int ecu; //0=apex, 1=adaptronic;2= OBD; 3= Dicktator ECU
int logging; // 0 Logging off , 1 Logging to file
int connectclicked =0;
QByteArray checksumhex;
QByteArray recvchecksumhex;
Connect::Connect(QObject *parent) :
QObject(parent),
m_serialport(Q_NULLPTR),
m_dashBoard(Q_NULLPTR),
m_gopro(Q_NULLPTR),
m_gps(Q_NULLPTR),
m_adaptronicselect(Q_NULLPTR),
m_apexi(Q_NULLPTR),
m_nissanconsult(Q_NULLPTR),
m_OBD(Q_NULLPTR),
m_sensors(Q_NULLPTR),
m_haltechCANV2(Q_NULLPTR),
m_adaptronicCAN(Q_NULLPTR),
m_datalogger(Q_NULLPTR),
m_calculations(Q_NULLPTR)
{
getPorts();
m_dashBoard = new DashBoard(this);
m_appSettings = new AppSettings(this);
m_gopro = new GoPro(this);
m_gps = new GPS(m_dashBoard, this);
m_adaptronicselect= new AdaptronicSelect(m_dashBoard, this);
m_apexi= new Apexi(m_dashBoard, this);
m_nissanconsult = new Nissanconsult(m_dashBoard, this);
m_OBD = new OBD(m_dashBoard, this);
m_sensors = new Sensors(m_dashBoard, this);
m_haltechCANV2 = new HaltechCAN(m_dashBoard, this);
m_adaptronicCAN = new AdaptronicCAN(m_dashBoard, this);
m_datalogger = new datalogger(m_dashBoard, this);
m_calculations = new calculations(m_dashBoard, this);
QQmlApplicationEngine *engine = dynamic_cast<QQmlApplicationEngine*>( parent );
if (engine == Q_NULLPTR)
return;
engine->rootContext()->setContextProperty("Dashboard", m_dashBoard);
engine->rootContext()->setContextProperty("AppSettings", m_appSettings);
engine->rootContext()->setContextProperty("GoPro", m_gopro);
engine->rootContext()->setContextProperty("GPS", m_gps);
engine->rootContext()->setContextProperty("Nissanconsult",m_nissanconsult);
engine->rootContext()->setContextProperty("Sens", m_sensors);
engine->rootContext()->setContextProperty("Logger", m_datalogger);
}
Connect::~Connect()
{
}
void Connect::checkifraspberrypi()
{
QString path = "/sys/class/backlight/rpi_backlight/brightness";
if (QFileInfo::exists(path))
{
m_dashBoard->setscreen(true);
}
else
{
m_dashBoard->setscreen(false);
}
}
void Connect::readdashsetup()
{
qDebug()<<"c++ file read";
QString path = "UserDash.txt";// this is just for testing
QFile inputFile(path);
if (inputFile.open(QIODevice::ReadOnly))
{
QTextStream in(&inputFile);
while (!in.atEnd())
{
QString line = in.readLine();
QStringList list = line.split(QRegExp("\\,"));
m_dashBoard->setdashsetup(list);
qDebug()<< list;
}
inputFile.close();
}
}
void Connect::setSreenbrightness(const int &brightness)
{
//This works only on raspberry pi
QFile f("/sys/class/backlight/rpi_backlight/brightness");
//f.close();
f.open(QIODevice::WriteOnly | QIODevice::Truncate);
QTextStream out(&f);
out << brightness;
//qDebug() << brightness;
f.close();
}
void Connect::setUnits(const int &units)
{
switch (units)
{
case 0:
m_dashBoard->setunits("metric");
break;
case 1:
m_dashBoard->setunits("imperial");
break;
default:
break;
}
}
void Connect::setWeight(const int &weight)
{
m_dashBoard->setWeight(weight);
qDebug() << "weight" << m_dashBoard->Weight();
}
void Connect::getPorts()
{
QStringList PortList;
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
PortList.append(info.portName());
}
setPortsNames(PortList);
// Check available ports every 1000 ms
QTimer::singleShot(1000, this, SLOT(getPorts()));
}
//function for flushing all Connect buffers
void Connect::clear() const
{
// m_Connectport->clear();
}
//function to open Connect port
void Connect::openConnection(const QString &portName, const int &ecuSelect)
{
ecu = ecuSelect;
//Apexi
if (ecuSelect == 0)
{
m_apexi->openConnection(portName);
}
//Adaptronic
if (ecuSelect == 1)
{
m_adaptronicselect->openConnection(portName);
}
//OBD
if (ecuSelect == 2)
{
m_OBD->openConnection(portName);
}
//Nissan Consult
if (ecuSelect == 3)
{
m_nissanconsult->LiveReqMsg(1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
m_nissanconsult->openConnection(portName);
}
//Adaptronic ModularCAN protocol
if (ecuSelect == 5)
{
m_adaptronicCAN->openCAN();
}
//Haltech V2 CAN protocol
if (ecuSelect == 6)
{
m_haltechCANV2->openCAN();
}
}
void Connect::closeConnection()
{
//Apexi
if (ecu == 0)
{
m_apexi->closeConnection();
}
//Adaptronic Select
if (ecu == 1)
{
m_adaptronicselect->closeConnection();
}
//OBD
if (ecu == 2)
{
m_OBD->closeConnection();
}
//Nissan Consult
if (ecu == 3)
{
m_nissanconsult->closeConnection();
}
//Adaptronic ModularCAN protocol
if (ecu == 5)
{
m_adaptronicCAN->closeConnection();
}
//Haltech V2 CAN protocol
if (ecu == 6)
{
m_haltechCANV2->closeConnection();
}
}
void Connect::update()
{
m_dashBoard->setSerialStat("Update started");
QProcess *process = new QProcess(this);
connect(process , SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(updatefinished(int, QProcess::ExitStatus)));
process->start("/home/pi/updatePowerTune.sh");
process->waitForFinished(6000000); // 10 minutes time before timeout
}
void Connect::updatefinished(int exitCode, QProcess::ExitStatus exitStatus)
{
qDebug() << "code" <<exitCode;
qDebug() << "status" <<exitStatus;
QString fileName = "/home/pi/build/PowertuneQMLGui";
QFile file(fileName);
if(QFileInfo::exists(fileName))
{
m_dashBoard->setSerialStat("Update Successful");
file.close();
}
else
{
m_dashBoard->setSerialStat("Update Unsuccessful");
}
}
connect.h
#ifndef CONNECT_H
#define CONNECT_H
#include <QtSerialPort/QSerialPort>
#include <QObject>
#include <QModbusDataUnit>
#include <QTimer>
#include <QProcess>
#include "calculations.h"
class SerialPort;
class Sensors;
class DashBoard;
class AdaptronicCAN;
class AdaptronicSelect;
class Apexi;
class HaltechCAN;
class Nissanconsult;
class OBD;
class datalogger;
class calculations;
class AppSettings;
class GoPro;
class GPS;
class OBD;
class Connect : public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList portsNames READ portsNames WRITE setPortsNames NOTIFY sig_portsNamesChanged)
public:
~Connect();
explicit Connect(QObject *parent = 0);
Q_INVOKABLE void checkifraspberrypi();
Q_INVOKABLE void readdashsetup();
Q_INVOKABLE void setSreenbrightness(const int &brightness);
Q_INVOKABLE void setUnits(const int &units);
Q_INVOKABLE void setWeight(const int &weight);
Q_INVOKABLE void clear() const;
Q_INVOKABLE void openConnection(const QString &portName, const int &ecuSelect);
Q_INVOKABLE void closeConnection();
Q_INVOKABLE void update();
public:
QStringList portsNames() const { return m_portsNames; }
private:
SerialPort *m_serialport;
DashBoard *m_dashBoard;
AppSettings *m_appSettings;
GoPro *m_gopro;
GPS *m_gps;
AdaptronicSelect *m_adaptronicselect;
Apexi *m_apexi;
Nissanconsult* m_nissanconsult;
OBD* m_OBD;
Sensors *m_sensors;
HaltechCAN *m_haltechCANV2;
AdaptronicCAN *m_adaptronicCAN;
datalogger *m_datalogger;
calculations *m_calculations;
QStringList m_portsNames;
QStringList *m_ecuList;
QThread* CALCThread;
QProcess process;
signals:
void sig_portsNamesChanged(QStringList portsNames);
public slots:
void updatefinished(int exitCode, QProcess::ExitStatus exitStatus);
void getPorts();
void setPortsNames(QStringList portsNames)
{
if (m_portsNames == portsNames)
return;
m_portsNames = portsNames;
emit sig_portsNamesChanged(portsNames);
}
};
#endif // CONNECT_H
dashbboard.cpp
#include <dashboard.h>
#include <QStringList>
#include <QDebug>
DashBoard::DashBoard(QObject *parent)
: QObject(parent)
{
}
void DashBoard::setdashsetup(const QStringList &dashsetup)
{
if (m_dashsetup == dashsetup)
return;
m_dashsetup = dashsetup;
emit dashsetupChanged(dashsetup);
}
//User Dashboard Stringlist
QStringList DashBoard::dashsetup() const { return m_dashsetup; }
dashboard.h
#ifndef DASHBOARD_H
#define DASHBOARD_H
#include <QStringList>
#include <QObject>
class DashBoard : public QObject
{
Q_OBJECT
//User Dashboard Stringlist dashsetup
Q_PROPERTY(QStringList dashsetup READ dashsetup WRITE setdashsetup NOTIFY dashsetupChanged)
public:
DashBoard(QObject *parent = 0);
//User Dashboard Stringlist
QStringList dashsetup() const;
signals:
QStringList m_dashsetup;
};
#endif // DASHBOARD_H
main.qml:
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import com.powertune 1.0
ApplicationWindow {
visible: true
width: 800
height: 480
minimumWidth: 800
minimumHeight: 480
title: qsTr("PowerTune ") + Dashboard.Platform + " Beta 24"
// visibility: "FullScreen"
color: "black"
Connections{
target: Dashboard
ondashsetupChanged: console.log("Dashboard has changed")
}
Item {
id: name
Component.onCompleted: Connect.checkifraspberrypi()
}
SwipeView {
id: view
currentIndex: 0
anchors.fill: parent
Loader {
id: firstPageLoader
source: ""
}
Loader {
id: secondPageLoader
source: ""
}
Loader {
id: thirdPageLoader
source: ""
}
Loader {
id: fourthPageLoader
source: ""
}
Item {
id:lastPage
SerialSettings{}
}
}
PageIndicator {
id: indicator
count: view.count
currentIndex: view.currentIndex
anchors.bottom: view.bottom
anchors.horizontalCenter: parent.horizontalCenter
}
}
The first letter of the property name is always capitalised in signal handlers:
onDashsetupChanged: console.log("Dashboard has changed")
Property Change Signal Handlers explains this:
A signal is automatically emitted when the value of a QML property changes. This type of signal is a property change signal and signal handlers for these signals are written in the form onChanged where is the name of the property, with the first letter capitalized.

How to delete QML window on closing signal (how to do it right)?

I have some problems with qt + qml: Sometimes I get segmentation fault trying to clear QQmlengine. And even if program doesn't crashes it has memory leaks. (sorry for my english). I think so because the larger qml file (many nested classes) the larger application process even after QQmlengine was deleted. So my question is what am I doing wrong in the code below?
//main.cpp
#include "qmlwindow.h"
#include <QApplication>
int QMLwindow::someValue = 0;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setQuitOnLastWindowClosed(false);
QSharedPointer<QMLwindow> w0(new QMLwindow);
QSharedPointer<QMLwindow> w1(new QMLwindow);
QSharedPointer<QMLwindow> w2(new QMLwindow);
w0.data()->createWindow();
w0.data()->createWindow();
w1.data()->createWindow();
w2.data()->createWindow();
return a.exec();
}
 
//qmlwindow.h
#ifndef QMLWINDOW_H
#define QMLWINDOW_H
#include <QObject>
#include <QQmlComponent>
#include <QQuickWindow>
#include <QSharedPointer>
#include <QDebug>
#include <QQmlEngine>
#include <QQmlContext>
class QMLwindow : public QObject
{
Q_OBJECT
private:
QSharedPointer<QQmlEngine> engine;
QQmlComponent *component;
QObject *windowObj;
QQuickWindow *loginWindow;
QVariant count;
public:
static int someValue;
explicit QMLwindow(QObject *parent = 0);
~QMLwindow();
void createWindow();
signals:
public slots:
void deleteWindow(QQuickCloseEvent *event);
};
#endif // QMLWINDOW_H
 
//qmlwindow.cpp
#include "qmlwindow.h"
QMLwindow::QMLwindow(QObject *parent) : QObject(parent)
{
someValue++;
count = someValue;
qDebug() << "construction of QMLwindow " << count.toInt();
}
QMLwindow::~QMLwindow()
{
qDebug() << "destruction of QMLwindow " << count.toInt();
}
void QMLwindow::createWindow(){
if(engine.isNull()){
engine = QSharedPointer<QQmlEngine>(new QQmlEngine);
component = new QQmlComponent(engine.data());
component->loadUrl(QUrl(QStringLiteral("qrc:/SomeWindow.qml")));
Q_ASSERT(component->isReady());
windowObj = component->create();
loginWindow = qobject_cast<QQuickWindow *> (windowObj);
engine.data()->rootContext()->setContextProperty("someValue", count) ;
connect(loginWindow, SIGNAL(closing(QQuickCloseEvent*)), SLOT(deleteWindow(QQuickCloseEvent*)));
loginWindow->show();
}
else loginWindow->show();
}
void QMLwindow::deleteWindow(QQuickCloseEvent*event){
Q_UNUSED(event)
if(!engine.isNull()) {
qDebug() << "loginWindow destruction";
engine.clear();
}
this->deleteLater();
}
 
//SomeWindow.qml
import QtQuick 2.3
import QtQuick.Window 2.0
Window {
width: 200
height: 200
color: "white"
Text{
text: someValue
anchors.centerIn: parent
}
}