I created a QML class like
import QtQuick 2.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Extras 1.4
Rectangle {
width: 80
height: 200
property double myVal: 15
Timer {
running: true
repeat: true
interval: 1
onTriggered: gauge.value = myVal
}
Gauge {
objectName: "gauge"
id: gauge
anchors.fill: parent
anchors.margins: 10
value: myVal
Behavior on value {
NumberAnimation {
duration: 1000
}
}
style: GaugeStyle {
valueBar: Rectangle {
implicitWidth: 16
color: Qt.rgba(gauge.value / gauge.maximumValue, 0, 1 - gauge.value / gauge.maximumValue, 1)
}
}
}
}
and I want to change value from my c++ file. To do this, I created a method which is setDataToGauge() and this method is like
void MainWindow::setDataToGauge(double newVal){
QQmlApplicationEngine engine;
QQmlComponent component(&engine, QUrl::fromLocalFile("gauge.qml"));
QObject object = component.create();
QObject *myGauge = object->findChild<QObject*>("gauge");
if(myGauge){
myGauge->setProperty("value",newVal);
qDebug() << myGauge->property("value");
}
}
this. However, it doesn't change the value of gauge. I tried different methods but it couldn't find the solution. When I drop
Behavior on value {
NumberAnimation {
duration: 1000
}
}
this part from QML file value is changing but view of gauge is not changing.
Also, I am adding to full code of my c++ file
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QDateTime>
#include <QtQuickWidgets/QQuickWidget>
#include <QtQml>
#include <QObject>
QObject *object;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
m_serial(new QSerialPort(this))
{
ui->setupUi(this);
ui->gaugeWidget->setSource(QUrl::fromLocalFile("gauge.qml"));
ui->gaugeWidget->setUpdatesEnabled(true);
QQmlApplicationEngine engine;
QQmlComponent component(&engine, QUrl::fromLocalFile("gauge.qml"));
object = component.create();
setDataToGauge(60.0);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setDataToGauge(double newVal){
QObject *myGauge = object->findChild<QObject*>("gauge");
if(myGauge){
QQmlProperty::write(myGauge, "value", newVal);
qDebug() << myGauge->property("value");
}
}
What is the problem in there?
In your attempt of solution you are creating another gauge, and that gauge is not shown because the QQmlApplicationEngine is a local variable that will be deleted when it finishes executing, in addition QQmlApplicationEngine expects a Window or ApplicationWindow, not an Item like Rectangle.
On the other hand it is advisable to use a qresource to store the .qml because otherwise you will have to copy them every time you compile the side of your executable.
It is also not recommended to access QML objects from C ++, it is better to export a C ++ object to QML using setContextProperty().
A simple solution is to create a signal, the signal is connected through Connections::
*.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
void setDataToGauge(double newVal);
signals:
void dataGaugeChanged(double dataToGauge); // signal
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
*.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QQmlEngine>
#include <QQmlContext>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->gaugeWidget->engine()->rootContext()->setContextProperty("MainWindow", this);
ui->gaugeWidget->setSource(QUrl("qrc:/gauge.qml"));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setDataToGauge(double newVal){
emit dataGaugeChanged(newVal);
}
gauge.qml
import QtQuick 2.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Extras 1.4
Rectangle {
width: 80
height: 200
Gauge {
id: gauge
anchors.fill: parent
anchors.margins: 10
Behavior on value {
NumberAnimation {
duration: 1000
}
}
style: GaugeStyle {
valueBar: Rectangle {
implicitWidth: 16
color: Qt.rgba(gauge.value / gauge.maximumValue, 0, 1 - gauge.value / gauge.maximumValue, 1)
}
}
}
Connections{
target: MainWindow
onDataGaugeChanged: gauge.value = dataToGauge
}
}
Another option is to create a Q_PROPERTY and make a binding:
*.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
Q_PROPERTY(double dataGauge READ dataGauge WRITE setDataGauge NOTIFY dataGaugeChanged)
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
double dataGauge() const;
void setDataGauge(double dataGauge);
signals:
void dataGaugeChanged();
private:
Ui::MainWindow *ui;
double mDataGauge;
};
#endif // MAINWINDOW_H
*.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QQmlEngine>
#include <QQmlContext>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->gaugeWidget->engine()->rootContext()->setContextProperty("MainWindow", this);
ui->gaugeWidget->setSource(QUrl("qrc:/gauge.qml"));
}
MainWindow::~MainWindow()
{
delete ui;
}
double MainWindow::dataGauge() const
{
return mDataGauge;
}
void MainWindow::setDataGauge(double dataGauge)
{
if(mDataGauge == dataGauge)
return;
mDataGauge = dataGauge;
emit dataGaugeChanged();
}
*.qml
import QtQuick 2.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Extras 1.4
Rectangle {
width: 80
height: 200
Gauge {
id: gauge
anchors.fill: parent
anchors.margins: 10
value: MainWindow.dataGauge // binding
Behavior on value {
NumberAnimation {
duration: 1000
}
}
style: GaugeStyle {
valueBar: Rectangle {
implicitWidth: 16
color: Qt.rgba(gauge.value / gauge.maximumValue, 0, 1 - gauge.value / gauge.maximumValue, 1)
}
}
}
}
Both solutions can be found in the following link.
Related
I have a dial and a slider, in mainwindow.cpp I have:
ui->quickWidget_3->setSource(QUrl("qrc:///slider.qml"));
ui->quickWidget_4->setSource(QUrl("qrc:///dial.qml"));
I want that when I move slider dial moves..
I wrote:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtQml>
#include <QtQuick>
#include <QSlider>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setStyleSheet("background-color:white");
ui->quickWidget->engine()->rootContext()->setContextProperty("yourObject",ui->horizontalSlider);
ui->quickWidget_2->engine()->rootContext()->setContextProperty("yourObject1",ui->horizontalSlider_3);
QObject* item = ui->quickWidget_3->rootObject();
QObject::connect(item, SIGNAL(moved()), SLOT(sliderMoved()));
ui->quickWidget_2->setSource(QUrl("qrc:///sl.qml"));
ui->quickWidget->setSource(QUrl("qrc:///qml.qml"));
ui->quickWidget_3->setSource(QUrl("qrc:///slider.qml"));
ui->quickWidget_4->setSource(QUrl("qrc:///dial.qml"));
ui->horizontalSlider->setStyleSheet("QSlider::groove:vertical {background-color:red; position:absolute; left:4px; right: 4px}");
//connect circularGauge e text
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_horizontalSlider_2_sliderMoved(int position)
{
ui->dial->setValue(position);
}
void MainWindow::sliderMoved()
{
QObject* slider = ui->quickWidget_3->rootObject();
QObject* dial = ui->quickWidget_4->rootObject();
qreal value = QQmlProperty::read(slider, "value").toReal();
QQmlProperty::write(dial, "value", value);
}
but it doesn't work
It is well documented here: Interacting with QML Objects from C++
Please try to provide full relevant working code in your questions next time, like I'm going to do in this answer. Doing so, you will increase the chance of an answer.
test.pro
QT += core gui widgets quickwidgets quickcontrols2
[...]
dial.qml
import QtQuick.Controls 2.12
Dial {
id: control
from: 0
to: 100
stepSize: 1
value: 0
}
slider.qml
import QtQuick.Controls 2.12
Slider {
id: control
from: 0
to: 100
stepSize: 1
value: 0
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void sliderMoved();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include <QQmlProperty>
#include <QQuickItem>
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->quickWidget_1->setSource(QUrl("qrc:/slider.qml"));
ui->quickWidget_2->setSource(QUrl("qrc:/dial.qml"));
QObject* item = ui->quickWidget_1->rootObject();
QObject::connect(item, SIGNAL(moved()), SLOT(sliderMoved()));
}
void MainWindow::sliderMoved()
{
QObject* slider = ui->quickWidget_1->rootObject();
QObject* dial = ui->quickWidget_2->rootObject();
qreal value = QQmlProperty::read(slider, "value").toReal();
QQmlProperty::write(dial, "value", value);
}
MainWindow::~MainWindow()
{
delete ui;
}
I try to embed this qml definition:
import QtQuick 2.0
Rectangle {
id: mqldefinition
color: "green"
width: 100
height: 100
Text {
id: text
text: "This is a text!"
font.pointSize: 14
anchors.centerIn: parent
}
}
within a Qt C++-widget:
qmlwidget.h
#include <QQuickWidget>
class QmlWidget
: public QQuickWidget
{
Q_OBJECT
public:
explicit QmlWidget(QWidget *parent = nullptr);
};
qmlwidget.h
#include "qmlwidget.h"
QmlWidget::QmlWidget(QWidget *parent)
: QQuickWidget(parent)
{
resize(100,100);
setSource(QUrl("qrc:/definition.qml"));
}
This widget shall be shown within the MainWindow as partly shown here:
mainwindow.cpp
#include "mainwindow.h"
#include "qmlwidget.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
auto qmlWidget = new QmlWidget(this);
qmlWidget->move(0,0);
}
But it is not shown :(
I found this in SO:
QQuickWidget *view = new QQuickWidget;
view->setSource(QUrl::fromLocalFile("myqmlfile.qml"));
view->show();
but I would like to implement it as derived class :)
One possible solution is to set the QmlWidget as centralWidget.
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QmlWidget *qmlWidget = new QmlWidget;
qmlWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
setCentralWidget(qmlWidget);
}
Another approach is to use layouts to handle the size of the widget.
Here is a QML map:
Map {
anchors.fill: parent
plugin: osmMapPlugin
center: QtPositioning.coordinate(56.006355, 92.860984)
zoomLevel: 14
MapPolyline {
line.width: 3
line.color: 'red'
path: [
{ latitude: -27, longitude: 153.0 },
{ latitude: -27, longitude: 154.1 },
{ latitude: -28, longitude: 153.5 },
{ latitude: -29, longitude: 153.5 }
]
}
}
How to change path from C++/qt? I tried this:
QML:
Map {
anchors.fill: parent
plugin: osmMapPlugin
center: QtPositioning.coordinate(56.006355, 92.860984)
zoomLevel: 14
MapPolyline {
line.width: 3
line.color: 'red'
path: map_path
}
}
C++:
map = new QQuickWidget();
map->setSource(QUrl("qrc:map.qml"));
QQmlContext *qml_map = map->rootContext();
QGeoPath *path = new QGeoPath();
path->addCoordinate(*(new QGeoCoordinate(56.0831528053, 92.8405031454)));
path->addCoordinate(*(new QGeoCoordinate(56.1, 93)));
qml_map->setContextProperty("map_path", path);
But I got a exception:
calling a private constructor of class 'QVariant':
qml_map->setContextProperty("map_path", path);
and
attempted to use of deleted function:
qml_map->setContextProperty("map_path", path);
UPD:
#hi-im-frogatto suggested that it was necessary to do so:
qml_map->setContextProperty("map_path", QVariant::fromValue(path));
It helped, the error no longer occurs. But the line is not drawn. Got error:
qrc:map.qml:30: ReferenceError: map_path is not defined
qrc:map.qml:21:5: QML Map: Plugin is a write-once property, and cannot be set again.
As it says #HiI'mFrogatto you should use QVariant::fromValue(), but it can not be used directly on the .qml side:
QGeoPath geopath;
geopath.addCoordinate(QGeoCoordinate(56.006355, 92.860984));
geopath.addCoordinate(QGeoCoordinate(56.1, 93));
geopath.addCoordinate(QGeoCoordinate(56.1, 92.777));
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("geopath", QVariant::fromValue(geopath));
what you have to do is access each element through a loop:
Map {
anchors.fill: parent
plugin: osmMapPlugin
center: QtPositioning.coordinate(56.006355, 92.860984)
zoomLevel: 10
MapPolyline {
id: pl
line.width: 3
line.color: 'red'
}
Component.onCompleted: {
var lines = []
for(var i=0; i < geopath.size(); i++){
lines[i] = geopath.coordinateAt(i)
}
pl.path = lines
}
}
But with this case we can not update the values of the QGeoPath, it is appropriate to implement a class that inherits from QObject and has as property to QGeoPath, since you can manipulate it from C++ or from QML.
main.cpp
#include <QGeoPath>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QTimer>
class PathController: public QObject{
Q_OBJECT
Q_PROPERTY(QGeoPath geopath READ geoPath WRITE setGeoPath NOTIFY geopathChanged)
public:
PathController(QObject *parent=0):QObject(parent){}
void test(){
mGeoPath.addCoordinate(QGeoCoordinate(56.006355, 92.860984));
mGeoPath.addCoordinate(QGeoCoordinate(56.1, 93));
mGeoPath.addCoordinate(QGeoCoordinate(56.1, 92.777));
QTimer *timer = new QTimer(this);
QObject::connect(timer, &QTimer::timeout, [this](){
mGeoPath.translate(0.001, -0.01);
emit geopathChanged();
});
timer->start(1000);
}
QGeoPath geoPath() const{return mGeoPath;}
void setGeoPath(const QGeoPath &geoPath){
if(geoPath == mGeoPath)
return;
mGeoPath = geoPath;
emit geopathChanged();
}
signals:
void geopathChanged();
private:
QGeoPath mGeoPath;
};
int main(int argc, char *argv[])
{
#if defined(Q_OS_WIN)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
PathController controller;
controller.test();
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("pathController", &controller);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
#include "main.moc"
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtLocation 5.6
import QtPositioning 5.6
Window {
visible: true
width: 640
height: 480
Plugin {
id: osmMapPlugin
name: "osm"
}
Map {
anchors.fill: parent
plugin: osmMapPlugin
center: QtPositioning.coordinate(56.006355, 92.860984)
zoomLevel: 10
MapPolyline {
id: pl
line.width: 10
line.color: 'red'
}
}
function loadPath(){
var lines = []
for(var i=0; i < pathController.geopath.size(); i++){
lines[i] = pathController.geopath.coordinateAt(i)
}
return lines;
}
Connections{
target: pathController
onGeopathChanged: pl.path = loadPath()
}
Component.onCompleted: pl.path = loadPath()
}
In this link you will find the complete example.
QQmlContext::setContextProperty accepts a QVariant and there's no any implicit conversion from QGeoPath to QVariant. However using the following method you can do this:
qml_map->setContextProperty("map_path", QVariant::fromValue(path));
More info: http://doc.qt.io/archives/qt-5.5/positioning-cpp-qml.html
Based on the answer I found here - How to set QML MapPolyline Path Property - I wrote a simple test-case which is correct, works and, most importantly, is simpler than the accepted answer on this question.
The principle is simple - we can wrap our QGeoCoordinates in QVariants. We can add the QVariants to a QVariantList, and pass that directly to the QML MapPolyline.path property.
Even better, if we do this with a C++ class' Q_PROPERTY value, we don't even have to have QML logic to read or re-read the property when it changes.
Finally, with this method you can call setContextProperty after the QQmlWidget has loaded its source and begun displaying, which is useful if, for example, your QQmlWidget is part of a Qt Designer form file instead of added explicitly in C++.
Lets take a look at how this looks in practice - I'm going to create a class called RouteProvider which provides the path:
#ifndef ROUTEPROVIDER_H
#define ROUTEPROVIDER_H
#include <QObject>
#include <qqml.h>
#include <QMetaClassInfo>
#include <QGeoPath>
class RouteProvider : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantList path READ path NOTIFY pathUpdated)
QML_ELEMENT
public:
explicit RouteProvider(QObject *parent = nullptr);
QVariantList path();
signals:
void pathUpdated();
private:
QVariantList m_path;
};
#endif // ROUTEPROVIDER_H
To pass this class as a context property, the following needs to be true:
The class must be a subclass of QObject
This might actually be something you can skip using Q_GADGET and Q_REGISTER_METATYPE but that way lies madness
the class must use the QML_ELEMENT macro in the private part of its declaration
Note that your m_path and class functions can, in theory, be anything and do anything. The important aspects are:
The path function should return the QVariantList of QVariant::fromValue(QGeoCoordinate) values
Functions that change the path should emit the pathUpdated signal.
Looking at the .cpp file for this example is very simple:
#include "routeprovider.h"
RouteProvider::RouteProvider(QObject *parent) : QObject(parent)
{
m_path.append(QVariant::fromValue(QGeoCoordinate(51.50648, -0.12927)));
m_path.append(QVariant::fromValue(QGeoCoordinate(51.50826, -0.12599)));
}
QVariantList RouteProvider::path()
{
return m_path;
}
For the sake of this demonstration, I'm just creating a line between two coordinates and returning the path.
I'm going to create a QMainWindow with a QQmlWidget as its central widget, then set an instance of this class as a context property.
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "routeprovider.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
RouteProvider m_provider;
};
#endif // MAINWINDOW_H
To demonstrate this method still works even after the QML file has been loaded, I'm loading the QML file first, then setting the context property:
#include "mainwindow.h"
#include <QQuickWidget>
#include <QQmlContext>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
auto centralWidget = new QQuickWidget(this);
centralWidget->setSource(QUrl{"qrc:/CentralMap.qml"});
centralWidget->rootContext()->setContextProperty("routeProvider", &m_provider);
centralWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
this->setCentralWidget(centralWidget);
this->resize(400, 400);
}
MainWindow::~MainWindow()
{
}
And here's the simplest kind of QML file which still demonstrates this in action:
import QtQuick 2.0
import QtPositioning 5.12
import QtLocation 5.15
Item {
Plugin {
id: mapPlugin
name: "osm"
}
Map {
anchors.fill: parent
zoomLevel: 14
plugin: mapPlugin
MapPolyline {
id: line
path: routeProvider.path
line.width: 15
line.color: 'red'
}
}
}
Place it in a .qrc file to make it available to the program at run-time.
Finally, a default-generated main function starts our application:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Result:
I am trying to send a list from QML to c++. I've tried with a string and an integer with success but when I try with a QVariant I get the error:
QObject::connect: No such slot MyClass::cppSlot(QVariant) in ../test_2206/main.cpp:31
My main.qml
import QtQuick 2.4
import QtQuick.Layouts 1.1
import Material.ListItems 0.1 as ListItem
import Material.Extras 0.1
import QtQuick.Controls 1.3 as QuickControls
import QtQuick.Controls 1.4
import Material 0.2
Window {
visible: true
property var listCloud: ["nuage1", "nuage2", "nuage3", "nuage4"]
id: item
width: 100; height: 100
signal qmlSignal(variant msg)
/* MouseArea {
anchors.fill: parent
onClicked: item.qmlSignal("Hello from QML")
}*/
Rectangle{
id:sousRect
color:"red"
width:100; height:100
Button{
id:buttonTest
onClicked: {
item.qmlSignal(listCloud)
}
}
}
}
My main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlProperty>
#include <QQmlComponent>
#include <QDebug>
#include "myclass.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
QQmlComponent component(&engine, QUrl(QStringLiteral("qrc:/main.qml")));
QObject *object = component.create();
MyClass myClass;
QObject::connect(object, SIGNAL(qmlSignal(QVariant)),
&myClass, SLOT(cppSlot(QVariant)));
return app.exec();
}
My myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QDebug>
#include <QString>
#include <QList>
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass(QObject *parent = 0);
signals:
public slots:
void cppSlot(QVariant &msg);
};
#endif // MYCLASS_H
My myclass.cpp
#include "myclass.h"
MyClass::MyClass(QObject *parent):
QObject(parent)
{
}
void MyClass::cppSlot(QVariant &msg){
qDebug() << "c++: bien reçu chef " << msg;
}
I don't understand why I can't put a QVariant parameter in this signal.
Any help is welcome :)
Change your slot to receive his parameter by value, rather than by reference. Like this:
void cppSlot(QVariant msg);
I think it has something to do with QML refusing to pass Window's property by reference. Anyway, Qt often sends signal by-value even if your signal/slot signature[s] declare arguments by-reference. For more on the topic see this and that
Don't use references between QML and C++, they won't work.
void cppSlot(QVariant & msg);
You can also create Q_INVOKABLE function in C++ and call it directly from QML. Here is how this looks like:
main.cpp:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlProperty>
#include <QQmlComponent>
#include <QDebug>
#include "myclass.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
auto myobject = new MyClass(&app);
engine.rootContext()->setContextProperty(QStringLiteral("myobject"), myobject);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
{
return -1;
}
return app.exec();
}
mycass.h:
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QDebug>
#include <QString>
#include <QList>
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass(QObject *parent = 0);
Q_INVOKABLE void cppSlot(QVariant msg);
};
#endif // MYCLASS_H
myclass.cpp:
#include "myclass.h"
MyClass::MyClass(QObject *parent):QObject(parent){}
void MyClass::cppSlot(QVariant msg)
{
qDebug() << "c++: bien reçu chef " << msg;
}
main.qml:
import QtQuick 2.4
import QtQuick.Layouts 1.1
import Material.ListItems 0.1 as ListItem
import Material.Extras 0.1
import QtQuick.Controls 1.3 as QuickControls
import QtQuick.Controls 1.4
import Material 0.2
Window
{
visible: true
property var listCloud: ["nuage1", "nuage2", "nuage3", "nuage4"]
id: item
width: 100; height: 100
Rectangle
{
id:sousRect
color:"red"
width:100; height:100
Button
{
id:buttonTest
onClicked: myobject.cppSlot(listCloud)
}
}
}
But if you like to use SIGNAL SLOTS there is Connections Object in QML. Your main.qml will look then like that:
Window
{
visible: true
property var listCloud: ["nuage1", "nuage2", "nuage3", "nuage4"]
id: item
width: 100; height: 100
Connections
{
target: buttonTest
onClicked: myobject.cppSlot(listCloud)
}
Rectangle
{
id:sousRect
color:"red"
width:100; height:100
Button
{
id:buttonTest
}
}
}
Q_INVOKABLE is nothing else as an public SLOT, it will be called through meta-object system.
this example is supposed to read the string from TextInput and display it in another Rectangle on click of the mouse. However, it does not. Why?
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QDeclarativeView>
#include <QDeclarativeContext>
#include <QObject>
#include <QString>
class MainWindow : public QDeclarativeView
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
};
class Data : public QObject
{
Q_OBJECT
Q_PROPERTY(QString teamName READ getTeamName WRITE setTeamName NOTIFY nameChanged)
public:
Data(QObject *parent = 0);
~Data();
public:
QString getTeamName();
void setTeamName(QString &);
signals:
void nameChanged();
private:
QString n_teamName;
};
#endif // MAINWINDOW_H
//mainwindow.cpp
#include "mainwindow.h"
#include <QDeclarativeView>
#include <QDeclarativeContext>
#include <QString>
#include <QObject>
MainWindow::MainWindow(QWidget *parent)
: QDeclarativeView(parent)
{
}
MainWindow::~MainWindow()
{
}
Data::Data(QObject *parent) : QObject(parent)
{
//n_teamName = "Ahoj";
}
Data::~Data(){
}
QString Data::getTeamName(){
return n_teamName;
}
void Data::setTeamName(QString &newName){
if(newName != n_teamName){
n_teamName = newName;
emit nameChanged();
}
}
//main.cpp
#include "mainwindow.h"
#include <qdeclarative.h>
#include <QApplication>
#include <QDeclarativeView>
#include <QDeclarativeContext>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
Data d;
qmlRegisterType<Data>("NData", 1, 0, "Data");
w.rootContext()->setContextProperty("data", &d);
w.setSource(QUrl::fromLocalFile("../klik/Main.qml"));
w.show();
return a.exec();
}
//main.qml
// import QtQuick 1.0 // to target S60 5th Edition or Maemo 5
import QtQuick 1.1
import NData 1.0
Rectangle {
id: root
width: 600
height: 400
Rectangle{
id: text
...
TextInput{
anchors.fill: text
anchors.margins: 3
focus: true
}
}
Rectangle{
...
Text{
id: copyText
anchors.centerIn: copy
text: data.setTeamName()
}
}
Rectangle{
id: klik
...
MouseArea{
...
onClicked: {
copyText.text = data.teamName
}
}
}
}
It lets out the error: TypeError: Result of expression 'data.setTeamName' [undefined] is not a function.
Main.qml:51: Error: Cannot assign [undefined] to QString
teamName is a property of data, so simply use assign operator like data.teamName = 'some text';
Probably you should add id field to your TextInput like
TextInput{
id: textInput
anchors.fill: text
anchors.margins: 3
focus: true
}
And change onClicked, so
MouseArea{
...
onClicked: {
data.teamName = textInput.text
copyText.text = data.teamName // copyText.text = textInput.text is fine too
}
}
I believe your actual exception is due to the following line
text: data.setTeamName()
setTeamName is a private function on your data object, that is not exposed as a slot, and is thus undefined when called and assigned to text. Nevermind the fact that it makes no sense to call the set when you are performing an assignment. I'm assuming this was supposed to be data.getTeamName().