I want to connect QML Signals to c++ functions. I do not really understand how I can get the right item. Right now I try it in the following way, which is not working (Also, would there be easier ways?), here is the code I tried:
main.cpp:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "include/myclass.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
QQmlComponent component(&engine, "qrc:/Page1.qml");
QObject *item = component.create();
MyClass myClass;
QObject::connect(item, SIGNAL(testSignal()),&myClass,SLOT(cppSlot()));
return app.exec();
}
main.qml:
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 800
height: 460
Page1 {
id: page1
visible: true
}
}
Page1.qml:
import QtQuick 2.7
import QtQuick.Window 2.2
Item {
width: 800
height: 460
signal testSignal()
CustomButton {
id: cppSignalButton
x: 14
y: 55
buttonText: "Test CPP Signal"
onButtonClicked: {
testSignal();
}
}
}
CustomButton.qml:
import QtQuick 2.7
import QtQuick.Window 2.2
Rectangle {
id: root
width: 200
height: 50
color: "#000000"
border.color: "#FFFFFF"
property string buttonText
signal buttonClicked()
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked:{
root.buttonClicked();
}
}
Text {
id: text1
x: 105
y: 31
color: "#ffffff"
text: buttonText
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: 20
}
}
and myclass.cpp:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <iostream>
#include <fstream>
#include <QQuickItem>
#include <QQuickView>
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass(){
};
public slots:
void cppSlot() {
std::ofstream textfile;
textfile.open("test.txt");
textfile << "Signal worked" << std::endl;
textfile.close();
qInfo( "Called the C++ slot" );
}
};
First you should read this article: Integrating QML and C++
You can invoke your MyClass object method from qml in the following way:
//main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "include/myclass.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
MyClass myClass;
engine.rootContext()->setContextProperty("myClass", &myClass);
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
return app.exec();
}
//Page1.qml
import QtQuick 2.7
import QtQuick.Window 2.2
Item {
width: 800
height: 460
signal testSignal()
CustomButton {
id: cppSignalButton
x: 14
y: 55
buttonText: "Test CPP Signal"
onButtonClicked: {
myClass.cppSlot(); //now you can use the context property to invoke your slot
}
}
}
Related
I use open source qt5.9 for an embedded device.
I wanna to use virtual keyboard in my qml project. I know I should add a static link in .pro file like :
static {
QT += svg
QTPLUGIN += qtvirtualkeyboardplugin
}
and also add
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard"));
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
to main.cpp file to use the virtual keyboard. but my virtual keyboard does not fire when I click on my text object:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.VirtualKeyboard 2.1
Window {
visible: true
width: 640
height: 480
TextInput {
id: textInput;
text:"ssssss"
height: 120;
width: parent.width - 2;
anchors.bottom: keyboard.top
color: "#000000"; // black
// http://doc.qt.io/qt-5/qinputmethod.html#properties
focus: Qt.inputMethod.visible;
verticalAlignment: TextInput.AlignVCenter;
}
}
It solved.
just put the kind of input for each lineedit . like this :
InputPanel{
id:inputpanel
visible:active
y:active?parent.height - inputpanel.height : parent.height
anchors.left: parent.left
anchors.right: parent.right
}
TextInput{
id:input
inputMethodHints: Qt.ImhDigitsOnly
focus: Qt.inputMethod.visible;
text: "123211"
}
TextInput{
id:input2
anchors.top:input.bottom
inputMethodHints: Qt.ImhLowercaseOnly
focus: Qt.inputMethod.visible;
text: "123211"
}
I have this code in Qt
int main(int argc, char *argv[]) {
QGuiApplication app(argc,argv);
QQuickView view;
QUrl q(QStringLiteral("QML:///places_map.qml"));
view.setSource(QUrl(QStringLiteral("qrc:///places_map.qml")));
//I've tried this to init qml properties
QObject *object = view.rootObject();
object->setProperty("latitude", 48.4656371);
object->setProperty("longitude", 31.04900455);
QQuickItem *item = view.rootObject();
item->setProperty("device_latitude", 48.4656371);
item->setProperty("device_longitude", 35.04900455);
}
And my qml file:
import QtQuick 2.0
import QtPositioning 5.5
import QtLocation 5.6
Rectangle {
width: 720
height: 480
property double latitude: 0
property double longitude: 0
property double device_latitude: 0 //48.4656371
property double device_longitude: 0 //35.54900455
property variant location: QtPositioning.coordinate(latitude, longitude)
property variant deviceLocation: QtPositioning.coordinate(device_latitude, device_longitude)
Plugin {
id: myPlugin
name: "osm"
}
PlaceSearchModel {
id: searchModel
plugin: myPlugin
searchTerm: "Pizza"
searchArea: QtPositioning.circle(deviceLocation)
Component.onCompleted: update()
}
Map {
id: map
anchors.fill: parent
plugin: myPlugin;
center: location
zoomLevel: 13
MapItemView {
model: searchModel
delegate: MapQuickItem {
coordinate: deviceLocation //QtPositioning.coordinate(device_latitude, device_longitude)
anchorPoint.x: image.width * 0.5
anchorPoint.y: image.height
sourceItem: Column {
Image { id: image; source: "marker.png" }
Text { text: title; font.bold: true }
}
}
}
}
}
In qml code properties double latitude and longitude set the view on map
but map shows place with latitude = 0 and longtitude = 0
If I set the correct coordinates in qml code everything works
How can I init this value from c++ code so that map will show my city ?
Using Q_PROPERTY would be better. Exposing Attributes of C++
I have it working like this:
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include <QQuickView>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickView view;
view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
QQuickItem *item = view.rootObject();
item->setProperty("number", 22.002);
view.show();
return app.exec();
}
main.qml
import QtQuick 2.4
import QtQuick.Window 2.2
Rectangle{
visible: true
width: 640
height: 480
property double number : 0
Text {
id: textEdit
text: number
verticalAlignment: Text.AlignVCenter
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 20
}
}
I get the "qrc:/main_left.qml:23: ReferenceError: CppClass is not defined" when I run the below code. This code tries to change the position of a rectangle in a window.
Main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "cppclass.h"
#include "bcontroller.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
//QGuiApplication app(argc, argv);
BController c;
CppClass cppClass;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("CppClass", &cppClass);
engine.load(QUrl(QStringLiteral("qrc:/main_left.qml")));
return app.exec();
}
main_left.qml
import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Controls 1.2
Rectangle {
visible: true
width: 640
height: 480
property int index: 0
Text {
text: controller.name
anchors.centerIn: parent
}
Image{
id:imageLeft
anchors.fill: parent
source:"imageLeft.jpg";
}
Connections {
target: CppClass
onPosUpdate: {
rect.x = currentPos
}
}
Button {
id: button1
x: 163
y: 357
text: qsTr("Change Position")
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.horizontalCenter: parent.horizontalCenter
onClicked: CppClass.getCurrentPos()
}
Rectangle {
id: rect
width: parent.width/2
height: parent.height/2
color: "transparent"
border.color: "red"
border.width: 5
radius: 10
}
MouseArea {
anchors.fill: parent
onClicked: controller.setName(++index)
}
}
cppclass.cpp
#include "cppclass.h"
#include <QtQuick>
#include <string>
CppClass::CppClass(QObject *parent) : QObject(parent)
{
}
CppClass::~CppClass()
{
}
void CppClass::getCurrentPos()
{
int pos = rand() % 400;
std::string s = std::to_string(pos);
QString qstr = QString::fromStdString(s);
emit posUpdate(qstr);
}
Please help!
I think there is a problem with CppClass declaration in your main.cpp => CppClass cppClass; and your CppClass constructor is CppClass::CppClass(QObejct *parent); which means that you are missing the constructor parameter.
Therefore,you have two possibilities
1st : Try use your class without QObject *parent
2nd: provide the QObject* parent for the contructor of CppClass when declaring it in main.cpp
I was reading the Qt documentation for the past couple of hours trying to figure out a way to make a UI created with Qt Quick UI (QML) communicate (interact) with C++ code (functions... etc.).
I've read the 5 or 6 similar questions on here to but I'm kind of confused, I have problems figuring out where to start or what to do first.
I'd appreciate it a lot if someone could take the time and list the steps needed to make this work.
What i've done so far. I tried doing ...>add new Item> C++ class but I failed with an error saying:" failed to add one or more files to project"> It seems like the files (.. .cpp and .h) are created, they were in the folder where the other project files were but not included in the project.
What I wanna do is just something simple like changing the text of the textedit through a C++ function or any other way possible.
//Test.qml (main.qml)
import QtQuick 2.1
import QtQuick.Window 2.0
Rectangle {
id: rootRect
width: Screen.width/2
height: Screen.height/2
color: "gray"
Button{}
Rectangle{
id: textField
width: 120
height: 40
color: "white"
x:274; y: 61
border.color: "blue"
border.width: 4
radius: 2
}
TextEdit {
id: display
x: 274
y: 61
width: 80
height: 20
text: qsTr("Text Edit")
font.pixelSize: 22
color: "black"
anchors.centerIn: textField
}
Rectangle{
id: inputField
width: textField.width
height: textField.height
border.color: "green"
border.width: 3
color: "white"
x: 140; y: 61
}
TextEdit{
id: input
color: "red"
font.pixelSize: 30
anchors.centerIn: inputField
text: "Some Text"
}
}
//Button.cpl
import QtQuick 2.0
import QtQuick.Window 2.0
Item {
property string defaultText: "New Text"
Rectangle{
id: button
width: rootRect.width/6
height: rootRect.height/8
color: "black"
x: 200; y: 200
radius: 10
}
MouseArea{
id: buttonClickArea
width: 0
anchors.rightMargin: 0
anchors.bottomMargin: 0
anchors.fill: button
onClicked: {
display.text = defaultText
}
}
}
Thank you for taking the time to read this and/or any replies.
Using Qt 5.4.0 and Qt Creator 3.3.0, create New Project:
Click New Project
Qt Quick Application
Click Choose...
Name the project and select where to place it
Click Next
Select Qt Quick 2.4 from the drop-down menu
Click Next
Select desired Kit(s)
Click Next
Click Finish
Now You should see open main.qml file with following code:
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
visible: true
MainForm {
anchors.fill: parent
mouseArea.onClicked: {
Qt.quit();
}
}
}
Change it to:
import QtQuick 2.4
import QtQuick.Window 2.2
//### New Code ###
import QtQuick.Controls 1.3
//################
Window {
id: window1
visible: true
//### New Code ###
width: 400
height: 500
TextArea {
id: textArea
readOnly: true
anchors.bottom: textInput.top
anchors.bottomMargin: 6
anchors.right: parent.right
anchors.rightMargin: 8
anchors.left: parent.left
anchors.leftMargin: 7
anchors.top: parent.top
anchors.topMargin: 7
}
TextField {
id: textInput
y: 470
height: 23
anchors.right: sendButton.left
anchors.rightMargin: 6
anchors.bottom: parent.bottom
anchors.bottomMargin: 7
anchors.left: parent.left
anchors.leftMargin: 7
}
Button {
id: sendButton
x: 328
y: 470
width: 64
height: 23
text: qsTr("Send")
anchors.bottom: parent.bottom
anchors.bottomMargin: 7
anchors.right: parent.right
anchors.rightMargin: 8
onClicked: {
CppClass.sendMessage(textInput.text, textArea);
textInput.text = "";
}
}
//################
}
Add C++ Class to Your project:
Right Mouse Click project name in Projects viewer
Click Add New...
Select C++ Class if not already selected
Click Choose...
In Class name filed enter "CppClass"
Set Base class to QObject
Click Next
Click Finish
Open cppclass.h and change it to:
#ifndef CPPCLASS_H
#define CPPCLASS_H
#include <QObject>
//### New Code ###
#include <QQuickItem>
#include <QQuickTextDocument>
#include <QTextDocument>
//################
class CppClass : public QObject
{
Q_OBJECT
public:
explicit CppClass(QObject *parent = 0);
~CppClass();
//### New Code ###
Q_INVOKABLE void sendMessage(const QString &msg, QQuickItem *textArea);
//################
signals:
public slots:
};
#endif // CPPCLASS_H
Open cppclass.cpp and change it to:
#include "cppclass.h"
CppClass::CppClass(QObject *parent) : QObject(parent)
{
}
CppClass::~CppClass()
{
}
//### New Code ###
void CppClass::sendMessage(const QString &msg, QQuickItem *textArea)
{
QTextDocument *textDocument = textArea->property("textDocument").value<QQuickTextDocument*>()->textDocument();
textDocument->setHtml(textDocument->toHtml() + "\n<b>Text sent to Cpp side:</b> <i>" + msg + "</i>");
}
//################
Open main.cpp and change it to:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
//### New Code ###
#include <QQmlContext>
#include "cppclass.h"
//################
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
//### New Code ###
CppClass cppClass;
engine.rootContext()->setContextProperty("CppClass", &cppClass);
//################
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Run Your application, type some text to Input Field and click send.
In response to Dynamic Remo comment here's another way to have QML and C++ communicate. This approach is based on C++ emitting a signal and QML acting upon it. Following is the code to get it working.
cppclass.h
#ifndef CPPCLASS_H
#define CPPCLASS_H
#include <QObject>
#include <QDateTime>
class CppClass : public QObject
{
Q_OBJECT
public:
explicit CppClass(QObject *parent = 0);
~CppClass();
Q_INVOKABLE void getCurrentTime();
signals:
void timeUpdate(QString currentTime);
public slots:
};
#endif // CPPCLASS_H
cppclass.cpp
#include "cppclass.h"
CppClass::CppClass(QObject *parent) : QObject(parent)
{
}
CppClass::~CppClass()
{
}
void CppClass::getCurrentTime()
{
emit timeUpdate(QDateTime::currentDateTime().toString("ddd dd MMMM yyyy hh:mm:ss.zzz"));
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "cppclass.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
CppClass cppClass;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("CppClass", &cppClass);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
main.qml:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls 1.2
Window {
id: rootWindow
width: 400
height: 400
visible: true
Connections {
target: CppClass
onTimeUpdate: {
initailizeDllMsg.text = currentTime
}
}
Text {
id: initailizeDllMsg
text: qsTr("{current time placeholder}")
font.pointSize: 14
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
Button {
id: button1
x: 163
y: 357
text: qsTr("Show current time")
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.horizontalCenter: parent.horizontalCenter
onClicked: CppClass.getCurrentTime()
}
}
I have so code in simple Qt Quick. I want to change the value of a property of qml element from my class.
myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
#include "qdebug.h"
#include <QtGui/QApplication>
#include <QDebug>
#include <QDeclarativeContext>
#include <QGraphicsObject>
#include <QVariant>
class myClass : public QObject
{
Q_OBJECT
public:
myClass(QObject *QMLObject) : m_QMLObject(QMLObject) {}
public slots:
void cppSlot(int number);
protected:
QObject *m_QMLObject;
};
#endif // MYCLASS_H
myclass.cpp
#include "myclass.h"
void myClass::cppSlot(int number) {
qDebug() << "Called the C++ slot with" << number;
QObject* textinput = m_QMLObject->findChild<QObject*>("textinput");
QObject* memo = m_QMLObject->findChild<QObject*>("memo");
QString str;
str=(textinput->property("text")).toString();
int a;
a=str.toInt();
a++;
QString str2;
str2=QString::number(a);
memo->setProperty("text", str+"+1="+str2);
}
main.cpp
#include <QtGui/QApplication>
#include "qmlapplicationviewer.h"
#include <QUrl>
#include <QDebug>
#include <QDeclarativeContext>
#include <QGraphicsObject>
#include "myclass.h"
Q_DECL_EXPORT int main(int argc, char *argv[])
{
QScopedPointer<QApplication> app(createApplication(argc, argv));
QmlApplicationViewer viewer;
myClass MyClass(viewer.rootObject());
viewer.rootContext()->setContextProperty("myObject", &MyClass);
viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
viewer.setSource(QUrl("qrc:qml/qml/Example/main.qml"));
viewer.showExpanded();
return app->exec();
}
main.qml
import QtQuick 1.0
Rectangle {
width: 300
height: 300
anchors.fill: parent
Column {
spacing: 5
anchors.centerIn: parent;
Rectangle {
id: button
width: 100
height: 30
color: "#e0b87b"
Text {
id: buttonLabel
text: "Start"
anchors.centerIn: parent;
}
MouseArea {
anchors.fill: parent
id: mouseArea
onClicked: myObject.cppSlot(1);
}
}
Rectangle {
id: textinputRect
width: 100
height: 18
color: "#e0b87b"
TextInput {
id: textinput
objectName: "textinput"
color: "#f51515";
selectionColor: "blue"
font.pixelSize: 12;
width: parent.width-4
anchors.centerIn: parent
focus: true
text:"1"
}
}
Rectangle {
id: memoRect
width: 100
height: 35
color: "#00b87b"
TextEdit{
id: memo
objectName: "memo"
wrapMode: TextEdit.Wrap
width:parent.width;
readOnly:true
}
}
}
}
When I run the application and click on the button, the application crashes. What am I doing wrong?
The rootObject is not instantiated yet, try something like this:
Q_DECL_EXPORT int main(int argc, char *argv[])
{
QScopedPointer<QApplication> app(createApplication(argc, argv));
QmlApplicationViewer viewer;
viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
viewer.setSource(QUrl("qrc:qml/qml/Example/main.qml"));
myClass MyClass(viewer.rootObject());
viewer.rootContext()->setContextProperty("myObject", &MyClass);
viewer.showExpanded();
return app->exec();
}
This way the rootObject() will point to the correct instance.
m_QMLObject is NULL. You need to load the QML from the resource components FIRST before trying to pass the rootObject() to the constructor of your "myClass" object or it will always be NULL.