Can Q_GADGET be the property of other Q_GADGET? - c++

When I tried to pass such object in qml to some QML component property, it's just crashed in release or hung up in debug on:
Currency& operator=(const Currency& that) = default;
currency.h:
#ifndef CURRENCY_H
#define CURRENCY_H
#include <QObject>
class Currency
{
Q_GADGET
Q_PROPERTY(QString name READ getName CONSTANT)
public:
Currency() : name("") {}
Currency(const Currency& that) = default;
Currency& operator=(const Currency& that) = default;
static Currency getUSD() {
return Currency("USD");
}
QString getName() {
return this->name;
}
private:
Currency(const QString& name) : name(name) {}
QString name;
};
#endif // CURRENCY_H
money.h:
#ifndef MONEY_H
#define MONEY_H
#include <QObject>
#include "currency.h"
class Money {
Q_GADGET
Q_PROPERTY(int amount READ getAmount CONSTANT)
Q_PROPERTY(Currency currency READ getCurrency CONSTANT)
public:
Money() :
Money(0, Currency())
{
}
Money(int amount, const Currency& currency) :
amount(amount),
currency(currency)
{
}
int getAmount() {
return this->amount;
}
Currency getCurrency() {
return this->currency;
}
private:
int amount;
Currency currency;
};
#endif // MONEY_H
factory.h:
#ifndef FACTORY_H
#define FACTORY_H
#include <QObject>
#include <QVariant>
#include "money.h"
class Factory : public QObject {
Q_OBJECT
Q_DISABLE_COPY(Factory)
public:
static Factory* instance() {
static Factory factory;
return &factory;
}
Q_INVOKABLE QVariant getMoney() {
return QVariant::fromValue(Money(12345, Currency::getUSD()));
}
private:
explicit Factory(QObject* parent = nullptr) :
QObject(parent)
{
}
};
#endif // FACTORY_H
main.cpp:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "factory.h"
#include "money.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterUncreatableType<Money>("test", 1, 0, "Money", "error");
qmlRegisterUncreatableType<Currency>("test", 1, 0, "Currency", "error");
qmlRegisterSingletonType<Factory>("test", 1, 0, "Factory",
[](QQmlEngine* engine, QJSEngine* scriptEngine) -> QObject* {
Q_UNUSED(scriptEngine)
Factory* instance = Factory::instance();
engine->setObjectOwnership(instance, QQmlEngine::ObjectOwnership::CppOwnership);
return instance;
});
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
main.qml:
import QtQuick 2.11
import QtQuick.Window 2.11
import test 1.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
MyItem {
value: {
var money = Factory.getMoney()
console.log(money)
return money
}
anchors.centerIn: parent
}
}
MyItem.qml:
import QtQuick 2.10
import QtQuick.Controls 2.3
Item {
id: root
property var value
width: label.width
height: label.height
Component.onCompleted: {
console.log(root.value)
}
Label {
id: label
text: root.value.currency.name
}
}

The error I get when executing your code is:
QMetaProperty::read: Unable to handle unregistered datatype 'Currency' for property 'Money::currency'
qml: Money(12345, )
According to the docs:
...
The property type can be any type supported by QVariant, or it can be
a user-defined type. In this example, class QDate is considered to be
a user-defined type.
...
In your case Currency is not supported by QVariant, so the solution is to use Q_DECLARE_METATYPE to be supported by QVariant:
class Currency
{
...
};
Q_DECLARE_METATYPE(Currency)
The complete example can be found in the following link.

Related

How to display data added via another class in C ++ to ListView, QML?

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

Method in class inheriting QObject is identified as property when called, doesn't run method

Basically, I have a project that I'm working on that's supposed to be a graphical game of Tic-Tac-Toe, and method calls to a class called "Game" (and any method calls at all) from the main qml file don't work. This error is returned:
TypeError: Property 'takeTurn' of object [object Object] is not a function
I've inherited QObject in this class, as well as included the Q_OBJECT macro and labelled the method as a Q_INVOKABLE.
The code compiles and links perfectly fine, this is a run-time error.
Here's the relevant code to help:
Game.hpp:
#define GAME_HPP
#include "Board.hpp"
#include <ostream>
#include <QObject>
class Game : public QObject
{
Q_OBJECT;
public:
//...
Q_INVOKABLE void takeTurn(int x, int y);
Q_INVOKABLE bool checkWin();
friend std::ostream& operator<<(std::ostream&, const Game&);
private:
char player_;
int turns_;
Board board_;
};
std::ostream& operator<<(std::ostream&, const Game&);
#endif // GAME_HPP
Game.cpp:
#include <iostream>
#include <QObject>
#include <QApplication>
using std::cout;
using std::endl;
//...
void Game::takeTurn(int x, int y)
{
QWindow* app = QApplication::topLevelWindows()[0];
cout << app << endl;
board_.setTile(x, y, player_);
player_ == 'X' ? player_ = 'O' : player_ = 'X';
turns_++;
}
//...
main.cpp:
#include "Game.hpp"
#include <iostream>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
using std::cout;
using std::endl;
Q_DECL_EXPORT int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType<Game>("com.myself", 1, 0, "Game");
qmlRegisterType<Board>("com.myself", 1, 0, "Board");
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);
engine.load(url);
return app.exec();
}
main.qml:
import QtQuick.Window 2.12
import com.myself 1.0
Window {
visible: true
width: 600
height: 600
title: qsTr("TicTacToe")
Item {
//...
MouseArea {
id: mouseArea1
anchors.fill: parent
onClicked: {
Game.takeTurn(0,0)
}
}
}
//...
}
//...
You have registered Game as a type, so what you need to do is create an object of that type, the error points to that problem:
// ...
Window {
visible: true
width: 600
height: 600
title: qsTr("TicTacToe")
Game {
id: game
}
// ...
Item {
// ...
MouseArea {
id: mouseArea1
anchors.fill: parent
onClicked: {
game.takeTurn(0,0)
}
}
}
// ...

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()
}
}
}
}

Passing QImage to QML, problemr with Image Provider

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?

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.