Problems with QML Connections
qrc:/main.qml:12:5: QML Connections: Detected function "onTop" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name.
qrc:/main.qml:13: ReferenceError: classA is not defined
as the picture shows,I cannot link to my Qt Signal
The problem is that QML cannot recognize my Qt signal void onTop(), how can I solve it? In Qt 6
I feel that QML has a lot of problems, it is not as easy to use as traditional QWidget, and there are few related materials.
head file
#pragma once
#include <QOBject>
#include <QUdpSocket>
class CupSingleHelper : public QObject
{
Q_OBJECT
Q_PROPERTY(NOTIFY onTop)
public:
CupSingleHelper(QObject *parent = nullptr);
~CupSingleHelper();
public:
void initSocket();
void setAppPid(qint64 app_pid);
void readData();
Q_INVOKABLE void printStr2();
public:
QUdpSocket* udp_socket = nullptr;
qint64 pid;
public slots:
void printStr();
signals:
void onTop();
};
cpp file
#include "CupSingleHelper.h"
#include <QNetWorkDatagram>
#include <qmessagebox.h>
#include <QDebug>
CupSingleHelper::CupSingleHelper(QObject* parent)
{
}
void CupSingleHelper::printStr()
{
qDebug() << "1111111";
}
void CupSingleHelper::printStr2()
{
qDebug() << "22222";
}
void CupSingleHelper::setAppPid(qint64 app_pid)
{
this->pid = app_pid;
}
void CupSingleHelper::initSocket()
{
QString data = ":start";
data.insert(0, QString::number(pid));
QByteArray byte_data = data.toLatin1();
udp_socket = new QUdpSocket(this);
bool sStatus = false;
sStatus = udp_socket->bind(QHostAddress::LocalHost, 8898);
if (sStatus == false) { udp_socket->writeDatagram(byte_data, QHostAddress::LocalHost, 8889); exit(1); }
connect(udp_socket, &QUdpSocket::readyRead, this, &CupSingleHelper::readData);
udp_socket->writeDatagram(byte_data, QHostAddress::LocalHost, 8889);
}
void CupSingleHelper::readData()
{
while (udp_socket->hasPendingDatagrams())
{
QNetworkDatagram datagram = udp_socket->receiveDatagram();
QString receive_data = datagram.data().data();
QString temp = receive_data.section(":", 0, 0);
if (temp.toInt() == pid)
{
break;
}
temp = receive_data.section(":", 1, 1);
if (temp.compare("start") == 0)
{
emit onTop();
}
}
}
CupSingleHelper::~CupSingleHelper()
{
if(udp_socket != nullptr)
{
delete[]udp_socket;
}
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QTranslator>
#include <QLocale>
#include "CupSingleHelper.h"
int main(int argc, char *argv[])
{
#if defined(Q_OS_WIN)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
CupSingleHelper cup_single_helper;
qint64 app_pid = QCoreApplication::applicationPid();
cup_single_helper.setAppPid(app_pid); //set process id
cup_single_helper.initSocket();//init udpsocket to listen
QTranslator t;
QLocale ql;
//Check system language and load
if (ql.language() == QLocale::Chinese)
{
bool status = t.load(":/x64/Debug/cuptools_zh.qm");
}
if (ql.language() != QLocale::English)
{
app.installTranslator(&t);
}
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
QQmlContext* rootContext = engine.rootContext();
rootContext->setContextProperty("classA",&cup_single_helper);
return app.exec();
}
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Window {
visible: true
width: 500
height: 720
title: qsTr("CupTools")
property var strd: "22222"
Connections {
target: classA
function onTop(){
label12.text = strd
}
}
Text {
id: label12
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
topMargin: 20
}
text:"11111"
}
Button {
id: mbutton
anchors.centerIn:parent
text: "Click"
onClicked: classA.printStr()
}
}
Your code has the following problems:
If you are going to declare a signal then you should not use Q_PROPERTY. Remove Q_PROPERTY(NOTIFY onTop).
You must establish the contexproperties before loading the .qml since otherwise at the time of loading those objects will not be defined.
If you want to connect a signal then the syntax is on<signal> where <signal> must be in camelcase format, in your case it must be onOnTop.
In Qt6 the versions of the QML modules are not necessary.
Since udp_socket is a child of the class then it is not necessary to eliminate it since it will cause a segmentation fault since you are eliminating the pointer 2 times.
#ifndef CUPSINGLEHELPER_H
#define CUPSINGLEHELPER_H
#include <QObject>
class QUdpSocket;
class CupSingleHelper : public QObject
{
Q_OBJECT
public:
CupSingleHelper(QObject *parent = nullptr);
~CupSingleHelper();
public:
void initSocket();
void setAppPid(qint64 app_pid);
void readData();
Q_INVOKABLE void printStr2();
public:
QUdpSocket* udp_socket = nullptr;
qint64 pid;
public slots:
void printStr();
signals:
void onTop();
};
#endif // CUPSINGLEHELPER_H
#include "cupsinglehelper.h"
#include <QNetworkDatagram>
#include <QUdpSocket>
CupSingleHelper::CupSingleHelper(QObject* parent):QObject(parent)
{
}
void CupSingleHelper::printStr()
{
qDebug() << "1111111";
}
void CupSingleHelper::printStr2()
{
qDebug() << "22222";
}
void CupSingleHelper::setAppPid(qint64 app_pid)
{
this->pid = app_pid;
}
void CupSingleHelper::initSocket()
{
QString data = ":start";
data.insert(0, QString::number(pid));
QByteArray byte_data = data.toLatin1();
udp_socket = new QUdpSocket(this);
bool sStatus = false;
sStatus = udp_socket->bind(QHostAddress::LocalHost, 8898);
if (sStatus == false) { udp_socket->writeDatagram(byte_data, QHostAddress::LocalHost, 8889); exit(1); }
connect(udp_socket, &QUdpSocket::readyRead, this, &CupSingleHelper::readData);
udp_socket->writeDatagram(byte_data, QHostAddress::LocalHost, 8889);
}
void CupSingleHelper::readData()
{
while (udp_socket->hasPendingDatagrams())
{
QNetworkDatagram datagram = udp_socket->receiveDatagram();
QString receive_data = QString::fromUtf8(datagram.data());
QString temp = receive_data.section(":", 0, 0);
if (temp.toInt() == pid)
{
break;
}
temp = receive_data.section(":", 1, 1);
if (temp.compare("start") == 0)
{
emit onTop();
}
}
}
CupSingleHelper::~CupSingleHelper()
{
}
#include "cupsinglehelper.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
CupSingleHelper cup_single_helper;
qint64 app_pid = QCoreApplication::applicationPid();
cup_single_helper.setAppPid(app_pid); //set process id
cup_single_helper.initSocket();//init udpsocket to listen
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
QQmlContext* rootContext = engine.rootContext();
rootContext->setContextProperty("classA",&cup_single_helper);
engine.load(url);
return app.exec();
}
import QtQuick
import QtQuick.Window
import QtQuick.Controls
Window {
visible: true
width: 500
height: 720
title: qsTr("CupTools")
property string strd: "22222"
Connections {
target: classA
function onOnTop(){
label12.text = strd
}
}
Text {
id: label12
anchors {
top: parent.top
horizontalCenter: parent.horizontalCenter
topMargin: 20
}
text:"11111"
}
Button {
id: mbutton
anchors.centerIn:parent
text: "Click"
onClicked: classA.printStr()
}
}
Related
I need to present all the data in the QLinkedList container (this was given by the task). I created two classes, DataObject for my delegates in ListView, Glav for container with DataObject objects. I have a button on which I add data to the container (the addItem function in the Glav class). The data is added but not displayed in the ListView. How to display them? I tried it through signals, it didn't work.
Here is the complete code of the project.
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QStringListModel>
#include <QQmlContext>
#include <QLinkedList>
#include <QQuickView>
#include <container.h>
#include <dataobject.h>
#include "glav.h"
//#include <container.cpp>
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
qmlRegisterUncreatableType<tile::Glav>( "Tile", 1, 0, "DataItem", "interface" );
qmlRegisterType<tile::Glav>( "Tile", 1, 0, "Glav");
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
main.qml
import QtQuick 2.12
import QtQuick.Controls 2.5
//import App 1.0
import Tile 1.0
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("Scroll")
// Container {
// id: container
// }
Glav {
id: glav
}
Row {
id: buttons
spacing: 20
padding: 10
anchors.horizontalCenter: parent.horizontalCenter
RoundButton {
padding: 20
text: "add item"
onClicked: {
glav.addItem()
listView.currentIndex = -1
}
}
Connections{
target: myModelObjectWhichWasSetAsContextProperty
onRowsInserted: console.log("rows were inserted")
}
ScrollView {
anchors.fill: parent
anchors.topMargin: buttons.implicitHeight + 10
ListView {
id: listView
width: parent.width
model: glav.list
//required model
delegate: Text {
property var d
d: model.modelData.id
text: model.modelData.name
}
removeDisplaced: Transition {
NumberAnimation { properties: "x,y"; duration: 100; easing.type: Easing.InOutQuad }
}
}
}
}
dataobject.h
#ifndef DATAOBJECT_H
#define DATAOBJECT_H
#include <QObject>
namespace tile {
class DataObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY changed)
Q_PROPERTY(QString color READ color WRITE setColor NOTIFY changed)
Q_PROPERTY(int id READ id WRITE setId NOTIFY changed)
public:
explicit DataObject(QString name = "Wana", QString color = "red", int id = 1, QObject *parent = nullptr);
QString name();
void setName(const QString &name);
QString color();
void setColor(const QString &color);
int id() const;
void setId(int id);
signals:
void changed();
private:
QString m_name;
QString m_color;
int m_id;
};
}
#endif // DATAOBJECT_H
dataobject.cpp
#include "dataobject.h"
#include <QDebug>
namespace tile {
DataObject::DataObject(QString name, QString color, int id, QObject* parent) :
QObject(parent)
, m_name (name)
, m_color (color)
, m_id (id)
{
//new DataObject();
qDebug() << m_name;
//emit changed();
}
QString DataObject::name()
{
return m_name;
}
void DataObject::setName(const QString &name)
{
m_name = name;
qDebug() << m_name;
emit changed();
}
QString DataObject::color()
{
return m_color;
}
void DataObject::setColor(const QString &color)
{
m_color = color;
emit changed();
}
int DataObject::id() const
{
return m_id;
}
void DataObject::setId(int id)
{
m_id = id;
emit changed();
}
}
glav.h
#ifndef GLAV_H
#define GLAV_H
#include <QObject>
#include <QLinkedList>
namespace tile {
class Glav : public QObject
{
Q_OBJECT
Q_PROPERTY( QLinkedList<QObject *> list READ list CONSTANT )
public:
explicit Glav(QObject *parent = nullptr);
//QLinkedList<QObject *> list();
//void setList(const QLinkedList<QObject *> &list);
Q_INVOKABLE QLinkedList<QObject *> pollist();
Q_INVOKABLE void addItem();
// Q_INVOKABLE QVariant pol();
signals:
void changed();
private:
QLinkedList<QObject *> m_list;
QLinkedList<QObject *> list();
};
}
#endif // GLAV_H
glav.cpp
#include "glav.h"
#include "dataobject.h"
#include <QDebug>
#include <QAbstractListModel>
namespace tile {
Glav::Glav(QObject *parent) : QObject(parent)
{
QLinkedList<QObject *> dataList = {
new DataObject("Item 1", "red"),
new DataObject("Item 2", "green"),
new DataObject("Item 3", "blue"),
new DataObject("Item 9", "yellow")
};
m_list << dataList;
QVariant::fromValue(m_list);
}
QLinkedList<QObject *> Glav::list()
{
return m_list;
}
//void Glav::setList(const QLinkedList<QObject *> &list)
//{
// m_list = list;
//}
//QVariant Glav::pol(){
// QVariant re = QVariant::fromValue(m_list);
// return re;
//}
QLinkedList<QObject *> Glav::pollist()
{
//qDebug() << QVariant::fromValue(m_list);
//QLinkedList<QObject *> f = m_list;
//QVariant::fromValue(m_list);
//qDebug() <<m_list;
return m_list;
}
void Glav::addItem()
{
qDebug() << m_list.count();
m_list << new DataObject();
qDebug() << m_list.count();
emit changed();
}
}
Your Glav class has a changed() signal but it doesn't do anything because your list property is constant (Q_PROPERTY( QLinkedList<QObject *> list READ list CONSTANT ))
You should change it to this:
Q_PROPERTY(QLinkedList<QObject*> list READ list NOTIFY changed)
That way you can let the ListView know that the list has just been changed by emitting the changed() signal.
Also, it's better to name the signal in accordance with the property it corresponds to: listChanged.
More info on how Q_PROPERTY works in the official documentation: https://doc.qt.io/qt-5/properties.html
I wrote this database front-end program with Qt and I used a C++ function to return the result of each query. However, I'm not able to assign the results to a list view.
MyObject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
class MyObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<QString> val READ val WRITE setVal NOTIFY valChanged)
public:
void setVal(QList<QString>);
QList<QString> val() const;
explicit MyObject(QObject *parent = nullptr);
Q_INVOKABLE int registernew(int Sno=0, QString Name="NULL",long long PhoneNo=0, QString Country="NULL",QString State="NULL", QString District="NULL", int PhoneLine=0,long long Whatsapp = 0);
Q_INVOKABLE int querydistrict(QString);
signals:
void valChanged();
private:
QList<QString> m_val;
};
#endif // MYOBJECT_H
MyObject.cpp
.............. void MyObject::setVal(QList<QString> list)
{
if(list != m_val)
{
m_val = list;
emit valChanged();
}
}
QList<QString> MyObject::val() const
{
return m_val;
}....................
main.cpp
#include <QGuiApplication>
#include<QQmlApplicationEngine>
#include "myobject.h"
#include<QQuickView>
#include<QQmlContext>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
///delete later!!
qmlRegisterType<MyObject>("io.qt.examples.MyObject", 1, 0, "MyObject");
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
page2.ui.qml
ScrollView {
id: scrollView
anchors.rightMargin: 20
anchors.leftMargin: 20
anchors.bottomMargin: 40
anchors.topMargin: 200
anchors.fill: parent
ListView {
id: listView
model: myobject.val
delegate: ItemDelegate {
text: modelData
}
}
}
Where am i going wrong? The list is never updated with values when i run the program. It is always blank. But the variable m_val, when I return it in MyObject.cpp and use qDebug to output it, outputs relevant strings.
You should not use QList<QString> but QStringList as it is registered. On the other hand if you are going to establish the data from C ++ since you indicate that it is the result of a query then that Q_PROPERTY is not of being written in QML. Finally, although it is not an error, it is better to register the classes before creating the QXApplication.
myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
class MyObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList val READ val NOTIFY valChanged)
public:
explicit MyObject(QObject *parent = nullptr);
QStringList val() const;
void setVal(QStringList val);
// other methods
signals:
void valChanged(QStringList val);
private:
QStringList m_val;
};
#endif // MYOBJECT_H
myobject.cpp
#include "myobject.h"
// other methods
QStringList MyObject::val() const{
return m_val;
}
void MyObject::setVal(QStringList val)
{
if (m_val == val)
return;
m_val = val;
emit valChanged(m_val);
}
main.cpp
// ...
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
qmlRegisterType<MyObject>("io.qt.examples.MyObject", 1, 0, "MyObject");
QGuiApplication app(argc, argv);
// ...
So when you do your query you must pass the result to setVal:
setVal(your_QStringList);
I'm trying to pass QImage to QML using Image Provider but all the time I'm getting error:
Failed to get image from provider: image://provider/im.
I'm writing a simple Media Player app, and I want to display cover image from Media Player metadata:
QVariant variant = _cpp_player->metaData(QMediaMetaData::CoverArtImage);
QImage image = variant.value();
I'm sending that QImage by signal, which is connected with slot in Image Provider class. That signal also invokes reload function in main.qml.
Here is the entire code:
main.cpp
#include <QUrl>
#include "player.h"
#include "imageprovider.h"
#include "imageprocessor.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
Player player;
QQmlApplicationEngine engine;
ImageProvider *imageProvider = new ImageProvider();
engine.rootContext()->setContextProperty("player", &player);
engine.addImageProvider("provider", imageProvider);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
imageprovider.h
#ifndef IMAGEPROVIDER_H
#define IMAGEPROVIDER_H
#include <QObject>
#include <QImage>
#include <QQuickImageProvider>
class ImageProvider : public QObject, public QQuickImageProvider
{
Q_OBJECT
public:
explicit ImageProvider(): QQuickImageProvider(QQuickImageProvider::Image) {}
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
public slots:
void imageChanged(QImage image);
private:
QImage _image;
};
#endif // IMAGEPROVIDER_H
imageprovider.cpp
#include "imageprovider.h"
#include <QDebug>
QImage ImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
if(_image.isNull())
{
qDebug() << "Image is null";
}
return _image;
}
void ImageProvider::imageChanged(QImage image)
{
_image = image;
}
player.h
#ifndef PLAYER_H
#define PLAYER_H
#include <QObject>
#include <QMediaPlayer>
#include <QMediaPlaylist>
#include <QMediaObject>
#include <QMediaMetaData>
#include <QList>
#include <QStringList>
#include "imageprovider.h"
class Player : public QObject
{
Q_OBJECT
Q_PROPERTY(QString songName READ songName WRITE setSongName NOTIFY songNameChanged)
Q_PROPERTY(QStringList list READ list NOTIFY playListUpdated)
QMediaPlayer *_cpp_player;
QMediaPlaylist *_cpp_playlist;
QString _songName;
QStringList strList;
ImageProvider *_cpp_provider;
public:
explicit Player(QObject *parent = nullptr);
QString songName() const;
QStringList list() const;
void setSongName(const QString &songName);
void addToPlayList(const QList<QUrl> &url);
Q_INVOKABLE void openFileDialog();
Q_INVOKABLE void positionChangedFromQML(const int &val);
Q_INVOKABLE void playListPositionChanged(const int &index);
public slots:
void playButtonClicked();
void pauseButtonClicked();
void stopButtonClicked();
void nextButtonClicked();
void previousButtonClicked();
void currentPlayListPosition(int index);
void positionChanged(qint64 pos);
void durationChanged(qint64 dur);
void stateChanged(QMediaPlayer::MediaStatus state);
signals:
void songNameChanged();
void posChanged(qint64 pos);
void songDuration(qint64 dur);
void songTime1(QString tim);
void songTime2(QString tim2);
void playListIsNotEmpty();
void playListUpdated();
void imageChanged(QImage image);
};
#endif // PLAYER_H
player.cpp
#include "player.h"
#include <QMediaPlayer>
#include <QMediaPlaylist>
#include <QMediaContent>
#include <QtDebug>
#include <QDateTime>
#include <QFileDialog>
class QMediaPlaylist;
class QMediaPlayer;
Player::Player(QObject *parent) : QObject(parent)
{
_cpp_player = new QMediaPlayer;
_cpp_playlist = new QMediaPlaylist;
_cpp_provider = new ImageProvider;
_cpp_player->setPlaylist(_cpp_playlist);
connect(_cpp_player, &QMediaPlayer::durationChanged, this, &Player::durationChanged);
connect(_cpp_player, &QMediaPlayer::positionChanged, this, &Player::positionChanged);
connect(this, &Player::imageChanged, _cpp_provider, &ImageProvider::imageChanged);
}
void Player::addToPlayList(const QList<QUrl> &url)
{
for (auto &el: url) {
_cpp_playlist->addMedia(el);
}
}
Q_INVOKABLE void Player::openFileDialog()
{
QFileDialog fileDialog;
fileDialog.setFileMode(QFileDialog::ExistingFiles);
fileDialog.setDirectory("/home");
QStringList formatList = {"*.mp3", "*.flac", "*.wav"};
fileDialog.setNameFilters(formatList);
if (fileDialog.exec() == QDialog::Accepted)
{
addToPlayList(fileDialog.selectedUrls());
for(int i = 0; i<fileDialog.selectedUrls().size(); ++i){
strList.append(fileDialog.selectedUrls().at(i).fileName());
emit playListIsNotEmpty();
emit playListUpdated();
}
}
}
QString Player::songName() const
{
return _songName;
}
QStringList Player::list() const
{
return strList;
}
void Player::setSongName(const QString &songName)
{
_songName = songName;
emit songNameChanged();
}
void Player::currentPlayListPosition(int index)
{
if(index!=-1){
setSongName(_cpp_player->metaData(QMediaMetaData::Title).toString());
}
}
void Player::durationChanged(qint64 dur)
{
stateChanged(QMediaPlayer::LoadedMedia);
emit songDuration(dur);
}
void Player::stateChanged(QMediaPlayer::MediaStatus state)
{
if (state == QMediaPlayer::LoadedMedia){
if (_cpp_player->isMetaDataAvailable())
{
setSongName(_cpp_player->metaData(QMediaMetaData::Title).toString());
QVariant variant = _cpp_player->metaData(QMediaMetaData::CoverArtImage);
QImage image = variant.value<QImage>();
emit imageChanged(image);
}
else
{
qDebug() << "No metadata.";
}
}
}
Q_INVOKABLE void Player::positionChangedFromQML(const int &val)
{
_cpp_player->setPosition(val);
}
void Player::playListPositionChanged(const int &index)
{
_cpp_playlist->setCurrentIndex(index);
}
void Player::positionChanged(qint64 pos)
{
emit posChanged(pos);
emit songTime1(QDateTime::fromTime_t((uint)pos/1000).toUTC().toString("mm:ss"));
emit songTime2((QDateTime::fromTime_t((uint)((_cpp_player->duration()/1000) - pos/1000))).toUTC().toString("mm:ss"));
}
void Player::playButtonClicked()
{
if(!_cpp_playlist->isEmpty()){
_cpp_player->play();
}
}
void Player::pauseButtonClicked()
{
_cpp_player->pause();
}
void Player::stopButtonClicked()
{
_cpp_player->stop();
}
void Player::nextButtonClicked()
{
if(_cpp_playlist->nextIndex()!=-1){
_cpp_playlist->next();
}
else
{
_cpp_player->stop();
_cpp_player->play();
}
}
void Player::previousButtonClicked()
{
if(_cpp_playlist->previousIndex()!=-1){
_cpp_playlist->previous();
}
else{
_cpp_player->stop();
_cpp_player->play();
}
}
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
Window {
Connections{
target: player
onPosChanged:{
newSlider.value = pos
}
onSongDuration:{
newSlider.stepSize = 1000
newSlider.to = dur
}
onSongTime1: {
newSlider.time1 = tim;
}
onSongTime2:{
newSlider.time2 = tim2;
}
onPlayListIsNotEmpty:{
toolBar.playState = "playClicked"
}
onImageChanged:{
cover.reload();
}
}
visible: true
width: 900
height: 600
title: "Media Player"
ToolBar {
id: toolBar
}
PlayListView{
id: playList
visible: false
}
AnotherSlider{
id:newSlider
anchors.bottom: toolBar.top
anchors.bottomMargin: 40
anchors.horizontalCenter: parent.horizontalCenter
sliderWidth: toolBar.width - 40
onMoved: {
player.positionChangedFromQML(value)
}
}
Rectangle{
id: albumImage
width: newSlider.width/2 - 10
height: newSlider.width/2 - 10
property int imageId: 0
Image {
id: cover
anchors.fill:albumImage
source: "image://provider/im"
function reload(){
var oldSource = source;
source = ""
source = oldSource
}
}
color: "white"
border.color: "black"
border.width: 5
radius: 5
anchors.left: newSlider.left
anchors.bottom: newSlider.top
anchors.bottomMargin: 40
}
}
What is wrong? How can I solve that?
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.
I have a project that I am working on, that will hopefully result in C++ code with a QML UI as a console, communicating with other consoles and equipment.
My test setup is based on a RaspBerry Pi running UDP comms (works fine into a normal Qt application).
I have tried to port to Qt Quick, and use a simple QML UI, but if I declare the subclass early in my "main.cpp" it doesn't connect properly.
If I declare it in the main.cpp "main" function, then I have scope issues with the subclass functions that I want to use to transfer data.
Open to suggestions / critique......and I am 100% sure that there is a "proper" way of doing this, so if anyone wants to point me at it......I will be enraptured!
Qt version is Qt5.3.
import QtQuick 2.2
import QtQuick.Controls 1.1
Rectangle {
width: 440; height: 150
color: "orange"
Column {
anchors.fill: parent; spacing: 20
Text {
text: rootItem.theChange
font.pointSize: 12; anchors.horizontalCenter: parent.horizontalCenter
}
}
}
// signalgrab.h
#ifndef SIGNALGRAB_H
#define SIGNALGRAB_H
#include <QObject>
#include <QUdpSocket>
#include <QString>
class SignalGrab : public QObject
{
Q_OBJECT
public:
explicit SignalGrab(QObject *parent = 0);
int SendValue();
void setupUDP();
signals:
public slots:
void readyRead();
private:
QUdpSocket *socket;
QHostAddress groupAddress;
};
#endif // SIGNALGRAB_H
// signalgrab.cpp
#include "signalgrab.h"
int i3 = 0;
SignalGrab::SignalGrab(QObject *parent) :
QObject(parent)
{
// create a QUDP socket
socket = new QUdpSocket(this);
socket->bind(QHostAddress("0.0.0.0"), 45454);
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
qDebug() << "Socket connected ok!";
}
void SignalGrab::readyRead()
{
// when data comes in
QByteArray buffer;
buffer.resize(socket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
socket->readDatagram(buffer.data(), buffer.size(),
&sender, &senderPort);
std::string s1 (buffer);
std::string s2 = s1.substr(26,sizeof(s1));
i3 = atoi(s2.data());
SendValue();
}
int SignalGrab::SendValue()
{
qDebug() << "sending i3 as: "<< i3;
return i3;
}
// main.cpp
#include <QtGui>
#include <QApplication>
#include <QQmlContext>
#include <QQuickView>
#include <QString>
#include "signalgrab.h"
int y=13;
// ///////////////////////////////////
//SignalGrab nc;
// ///////////////////////////////////
class Object : public QObject
{
Q_OBJECT
Q_PROPERTY(QString theChange READ getTheChange NOTIFY changeOfStatus)
public:
Object()
{
changeMe = false;
myTimer = new QTimer(this);
myTimer->start(5000);
connect(myTimer, SIGNAL(timeout()), this, SLOT(testSlot()));
}
QString getTheChange()
{
if (theValue == 0)
{
return "The Acid QML Test";
}
if (theValue == 1)
{
y = (fetchValue());
qDebug() << "New y!" << y;
return QString("Returning %1").arg(y);
}
return "nothing has happened yet";
}
int fetchValue()
{
// return (nc::SendValue());
return y;
}
Q_INVOKABLE void someFunction(int i)
{
if ( i == 0) {
theValue = 0;
}
if (i == 1) {
theValue = 1;
}
emit changeOfStatus(i);
}
signals:
void changeOfStatus(int i) ;
public slots:
void testSlot()
{
if (changeMe)
{
someFunction(0);
} else {
someFunction(1);
}
changeMe = !changeMe;
}
private:
bool changeMe;
int theValue;
QTimer *myTimer;
};
#include "main.moc"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
Object myObj;
// //////////////////////////////
SignalGrab nc; //added
// //////////////////////////////
nc.SendValue();
QQuickView view;
view.rootContext()->setContextProperty("rootItem", (QObject *)&myObj);
view.setSource(QUrl::fromLocalFile("main.qml"));
view.show();
return app.exec();
}