I am a newbie in QML, and cannot resolve a simple issue. I want to get access to the QML components from C++, but I cannot.
The pointer test is always 0. What can be the reason?
The code is the following:
main.cpp
int main(int argc, char *argv[])
{
QGuiApplication &app=reg6::Bonder::BonderGuiApplication::instance();
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QObject* test=engine.rootObjects().first()->findChild<QObject*> ("cameraArea");
test->setProperty("color","black");
return app.exec();
}
main.qml
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 1800
height: 900
SplitView
{
anchors.fill: parent
orientation: Qt.Vertical
SplitView {
Layout.fillHeight: true
SplitView {
orientation: Qt.Vertical
width:400
Layout.minimumWidth: 400
Layout.maximumWidth: 500
Camera {
id: cameraArea
height: 400
Layout.maximumHeight: 400
Layout.minimumHeight: 300
}
List {
id: listArea
}
}
Bonder {
id: mainArea
Layout.fillWidth: true
}
Properties {
id: propertiesArea
Layout.minimumWidth: 300
Layout.maximumWidth: 400
}
}
Error {
id: errorArea
Layout.minimumHeight: 100
height: 200
}
}
}
Camera.qml
import QtQuick 2.5
Rectangle {
color: "lightblue"
}
You have to set the objectName property also of the QML component to get a valid pointer to your QObject because T QObject::findChild(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const needs the objectName not the ID
Related
I have a QtQuick application. When the user tries to close the application, I want an "Are you sure?" window to pop up.
My main C++ class has this:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
And my main QML class has an application window:
ApplicationWindow {
id: root
...
}
Where and how would I catch the close event? I read about overriding closeEvent() from QMainWindow method or something, but I don't have a QMainWindow and I don't know where I'd put that code.
So I'd like to know how to prevent the app from closing and have something else happen instead, and how I'd close the app later when the user clicks "ok" in the confirmation dialog.
As far as I can see, the ApplicationWindow's "onClosing" only allows me to do some clean up before the inevitable close, but it doesn't prevent the close (please correct me if I'm wrong)
I solved it.
ApplicationWindow {
id: root
onClosing: close.accepted = false
}
This prevents the app from closing.
root.close()
This closes the app.
import QtQuick 2.13
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.13
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.3
ApplicationWindow {
property bool closing: false
MessageDialog {
id: exitMessageDialogId
icon: StandardIcon.Question
text: "Are you sure to exit?"
standardButtons: StandardButton.Yes | StandardButton.No
onYes: {
closing = true
mainWindowId.close()
}
}
onClosing: {
close.accepted = closing
onTriggered: if(!closing) exitMessageDialogId.open()
}
id: mainWindowId
}
In this case it just close current window.
//use Qt 5.11.2
// for android y desktop
import QtQuick 2.9
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("xxxx xxxx")
id: mainWindow
visible: true
//desision para salir
MessageDialog {
id: messageDialogQuit
title: "Deseas salir?"
icon: StandardIcon.Question
text: "xxxxxxxxxxxxxxxxxxxxxxxxx."
standardButtons: StandardButton.Yes |StandardButton.No
// Component.onCompleted: visible = true
onYes: Qt.quit()
// onNo: console.log("didn't copy")
}
onClosing:{
close.accepted = false
onTriggered: messageDialogQuit.open()
}
menuBar: MenuBar {
id: m_menu
LayoutMirroring.enabled: true
LayoutMirroring.childrenInherit: true
anchors.left: parent.left
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("Exit")
onTriggered: messageDialogQuit.open()
}
}
}
width: 400
height: 300
}
I am trying to interact with an qml object from C++ file using QtQuick. But unfortunatelly unsuccessfully for now. Any idea what Im doing wrong? I tried 2 ways how to do it, result of the first was that findChild() returned nullptr, and in second try I am getting Qml comnponent is not ready error. What is the proper way to do it?
main:
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
// 1-st attempt how to do it - Nothing Found
QObject *object = engine.rootObjects()[0];
QObject *mrect = object->findChild<QObject*>("mrect");
if (mrect)
qDebug("found");
else
qDebug("Nothing found");
//2-nd attempt - QQmlComponent: Component is not ready
QQmlComponent component(&engine, "Page1Form.ui.qml");
QObject *object2 = component.create();
qDebug() << "Property value:" << QQmlProperty::read(object, "mwidth").toInt();
return app.exec();
}
main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
Page1 {
}
Page {
}
}
}
Page1.qml:
import QtQuick 2.7
Page1Form {
...
}
Page1.Form.ui.qml
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
Item {
property alias mrect: mrect
property alias mwidth: mrect.width
Rectangle
{
id: mrect
x: 10
y: 20
height: 10
width: 10
}
}
findChild takes object name as first parameter. But not ID.
http://doc.qt.io/qt-5/qobject.html#findChild.
Here in your code, you are trying to query with id mrect. So it may not work.
Add objectName in your QML and then try accessing with findChild using object name.
Something like below (I did not try it. So chances of compile time errors):
Add objectName in QML
Rectangle
{
id: mrect
objectName: "mRectangle"
x: 10
y: 20
height: 10
width: 10
}
And then your findChild as shown below
QObject *mrect = object->findChild<QObject*>("mRectangle");
I am trying to use QML with C++ in QT, but for now unsuccessfully. I cannot access my QML element from the C++ code using rootObjects() function. What am I doing wrong?
qml part:
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
ApplicationWindow {
id: window
visible: true
width: 640
height: 520
title: qsTr("My app")
Item {
anchors.fill: parent
Rectangle {
id: rectangle1
x: 0
y: 0
width: 640
height: 370
color: "#ffffff"
}
Button {
id: startButton
x: 325
y: 425
text: qsTr("Start")
}
}
}
C++ Part:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
QObject *rootObject = engine.rootObjects().first();
qDebug() << rootObject->objectName();//prints ""
QObject *qmlObject = rootObject->findChild<QObject*>("window");// or "startButton"
//qDebug() << qmlObject->objectName(); //app fails, because window was not found
QList<QObject *> allQObjects = rootObject->findChildren<QObject *>();
for(int i=0;i< allQObjects.length();++i)
{
qDebug() << allQObjects[i]->objectName(); //prints everytime ""
}
qDebug() << "len: " << allPQObjects.length(); //prints 132
return app.exec();
}
At first: If you do not set a object name there will be no!
QML:
Rectangle { id : frame; objectName : "objFrame" color : "blue" }
Qt:
QObject *pRootObject = m_pQmlView->rootObject();
QObject *pobjFrame = m_pRootObject->findChild<QObject *>("objFrame");
The other way arround:
Qt:
m_pQmlView->rootContext()->setContextProperty( "_view", this );
QML:
Component.onCompleted: {
/********************** Connections ***************************/
// connect signal MyView::retranslate() with slot retranslate
_view.retranslate.connect(retranslate)
}
Need to add objectname to QML
ApplicationWindow {
id: window
objectName: "window"
...
}
Given my thoughts below am I barking up the wrong tree? Or provided the information below am I misusing Qt API to get the error in the title?
I am trying to modify the sample at http://doc.qt.io/qt-5/qtquick-scenegraph-openglunderqml-example.html to work with the default QtQuick project generated with Qt Creator 3.3.0 (opensource)
Based on Qt 5.4.0 (GCC 4.6.1, 64 bit).
After looking through the code the first thing that stands out to me is:
The samples main.cpp uses:
qmlRegisterType<Squircle>("OpenGLUnderQML", 1, 0, "Squircle");
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.setSource(QUrl("qrc:///scenegraph/openglunderqml/main.qml"));
view.show();
With some renaming my main.cpp uses
qmlRegisterType<MainScreen>("OpenGLUnderQML", 1, 0, "MainScreen");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
I am not sure if the difference in using a QQmlApplicationEngine over a QuickView could be causing my error:
QQmlApplicationEngine failed to load component qrc:/main.qml:23
Invalid attached object assignment
Where my main.qml looks like:
import QtQuick 2.4
import QtQuick.Window 2.2
import OpenGLUnderQML 1.0
import "qmlmodel"
Window {
id: mainWindow
width: 800
height: 600
visible: true
color: "black"
title: "Army Calculator"
objectName: "mainWindow"
ListView {
id: mainListView
anchors.fill: parent
objectName: "mainListView"
}
MainScreen {
SequentialAnimation on DeltaT {
NumberAnimation { to: 1; duration: 2500; easing.type: Easing.InQuad }
NumberAnimation { to: 0; duration: 2500; easing.type: Easing.OutQuad }
loops: Animation.Infinite
running: true
}
}
}
and the sample uses:
import QtQuick 2.0
import OpenGLUnderQML 1.0
Item {
width: 320
height: 480
Squircle {
SequentialAnimation on t {
NumberAnimation { to: 1; duration: 2500; easing.type: Easing.InQuad }
NumberAnimation { to: 0; duration: 2500; easing.type: Easing.OutQuad }
loops: Animation.Infinite
running: true
}
}
Rectangle {
color: Qt.rgba(1, 1, 1, 0.7)
radius: 10
border.width: 1
border.color: "white"
anchors.fill: label
anchors.margins: -10
}
Text {
id: label
color: "black"
wrapMode: Text.WordWrap
text: "The background here is a squircle rendered with raw OpenGL using the 'beforeRender()' signal in QQuickWindow. This text label and its border is rendered using QML"
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.margins: 20
}
}
As per request in comment below MainScreen.h is
#ifndef MAINSCREEN_H
#define MAINSCREEN_H
#include <QQuickItem>
class MainScreenRenderer;
class QQuickWindow;
class MainScreen : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(qreal DeltaT READ getDeltaT WRITE setDeltaT NOTIFY deltaTChanged)
public:
MainScreen();
~MainScreen();
qreal getDeltaT() const;
void setDeltaT(qreal deltaT);
signals:
void deltaTChanged();
public slots:
void sync();
void cleanup();
private slots:
void handleWindowChanged(QQuickWindow *win);
private:
qreal m_DeltaT;
MainScreenRenderer *m_Renderer;
};
#endif // MAINSCREEN_H
Property name should start with lowercase letter. You need to change DeltaT to deltaT.
MainScreen.h
Q_PROPERTY(qreal deltaT READ getDeltaT WRITE setDeltaT NOTIFY deltaTChanged)
main.qml
MainScreen {
SequentialAnimation on deltaT {
}
}
I'm new to QML. I cannot get these code working.
Model.qml
import QtQuick 1.1
XmlListModel {
source: "./test.xml"
query: "/tag1/tag2"
onSourceChanged: {
console.log("source changed:" + source)
reload()
}
XmlRole { name: "id"; query: "id/string()" }
XmlRole { name: "name"; query: "name/string()" }
}
View.qml
import QtQuick 1.1
ListView {
width: 200
}
TheDelegate.qml
import QtQuick 1.1
Rectangle {
width: parent.width
height: 20
Text {
text: id + ": " + name
}
}
Main.qml
import QtQuick 1.1
Item {
id: container
Model {
id: resultModel
objectName: "resultModel"
}
View {
id: resultView
model: resultModel
delegate: TheDelegate {}
}
}
And in my main.cpp:
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QDeclarativeView view;
view.setResizeMode(QDeclarativeView::SizeRootObjectToView);
view.setSource(QUrl::fromLocalFile("./TheMain.qml"));
view.show();
int rtnVal = app.exec();
return rtnVal;
}
When i run the project, it just shows nothing, no window displayed.
Thanks in advance.
EDIT:
I use the qmlviewer(4.8.4) to debug my qmls, and i get the warning:
TheDelegate.qml:18: ReferenceError: Can't find variable: name
But I have to name defined in the XmlRole.
You need to set Height as well for listview.
ListView {
width: 200
height: parent.height;
}