Accessing qml objects from loaded qml using cpp code - c++

I have a main.qml which loads Page1.qml using loaders. How can I find object 'whiteArea' within Page1.qml from my cpp code?
I am currently using the following to fetch an object and would like to obtain the loaded qml as well like this as well.
QObject * object = engine.rootObjects().at(0)->findChild<QObject *> ("yourObjectName");
main.qml
import QtQuick 2.3
import QtQuick.Controls 1.2
import myplugin 1.0
ApplicationWindow {
id:app
visible: true
width: 640
height: 480
title: qsTr(" World")
objectName: "Appwindow"
property ApplicationWindow appwindow:app
Label {
objectName: "label"
text: qsTr(" World")
anchors.centerIn: parent
}
MyItemTest{
objectName: "myItem"
anchors.fill: parent
}
Rectangle{
objectName: "Rectangle"
id:rect
width: 50
height: 50
color: "yellow"
}
Button {
objectName: "MyButton"
id: btnClick
text : "btn"
Loader { id: pageLoader }
onClicked: {
pageLoader.source = "Page1.qml"
}
}
}
Page1.qml
import QtQuick 2.0
import QtQuick 2.3
import QtQuick.Controls 1.2
import myplugin 1.0
Item {
Rectangle{
objectName: "whiteArea"
id:rect
width: 50
height: 50
color: "white"
}
}

From the Qt documentation:
The loaded object can be accessed using the item property.
So you should do some subsearch inside a loaded item, for example like this:
QObject * loader = engine.rootObjects().at(0)->findChild<QObject*>("loader");
qWarning() << loader;
QObject * item = qvariant_cast<QObject*>(QQmlProperty::read(loader,"item"));
qWarning() << item;
QObject *whiteArea = item->findChild<QObject *>("whiteArea");
qWarning() << whiteArea;
The output:
QQuickLoader(0x24918240, name = "loader")
QQuickItem(0x24919740)
QQuickRectangle(0x24919728, name = "whiteArea")

First of all , give Loader an object name property, like "loader".
then be sure at the time you running the below code , loader.item is set with"Page1.qml" then do something like this:
QObject* loader = m_engine->rootObjects()[0]->findChild<QObject*>("loader");
QObject* page= qvariant_cast<QObject *>(loader->property("item"));
QObject* whiteArea = page->findChild<QObject*>("whiteArea");

Related

Cannot use C++ QQuickPaintedItem Singleton in QML

I have to create a C++ singleton class, but it doesn't work in qml.
#include "myimage.h"
MyImage::MyImage(QQuickPaintedItem *parent)
{
}
MyImage* MyImage::myImage = new MyImage;
MyImage *MyImage::instance()
{
return myImage;
}
void MyImage::paint(QPainter *painter)
{
QRectF target(10.0, 20.0, 80.0, 60.0);
QRectF source(0.0, 0.0, 70.0, 40.0);
painter->setRenderHint(QPainter::Antialiasing, true);
painter->setRenderHint(QPainter::SmoothPixmapTransform, true );
painter->drawImage(target, this->m_Image, source);
}
const QImage &MyImage::getM_Image() const
{
return m_Image;
}
void MyImage::setM_Image(const QImage &mimage)
{
if (mimage != m_Image) {
m_Image = mimage;
emit m_ImageChanged();
}
}//This is my singleton class.
Then I register it in main.cpp.
QObject *getMySingletonImage(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine)
Q_UNUSED(scriptEngine)
return MyImage::instance();
}
...
qmlRegisterSingletonType<MyImage>("s0.image", 1, 0, "MyImage", &getMySingletonImage);
In QML:
import s0.image 1.0
MyImage{
}
I cannot run the program successfully.
qrc:/Camview_Page.qml:371:13: Element is not creatable.
Actually, I use the singleton class both in my backend and qml.
In my backend, I will get QImage type images but not be saved local, so I cannot use QUrl and I only figure out this method.
Expectation:
My backend pass images of QImage type to the singleton class, my singleton class realize the method of paint, my qml show the image.
BTW...my backend gets images from camera.
A singleton is already created for QML so you get that error message since by using "{}" you are trying to create the object.
In this case it is enough to set a parent and the size:
import QtQuick 2.15
import QtQuick.Window 2.15
import s0.image 1.0
Window {
id: root
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Component.onCompleted: {
MyImage.parent = root.contentItem
MyImage.width = 100
MyImage.height = 100
}
}
If you want to create a binding for example set anchors.fill: parent then you can use the Binding component, if you want to hear any signal then you must use Connections component.
import QtQuick 2.15
import QtQuick.Window 2.15
import s0.image 1.0
Window {
id: root
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Binding{
target: MyImage
property: "parent"
value: root.contentItem
}
Binding {
target: MyImage
property: "anchors.fill"
value: MyImage.parent
}
Connections{
target: MyImage
function onWidthChanged(){
console.log("width:", MyImage.width)
}
function onHeightChanged(){
console.log("height:", MyImage.height)
}
}
}

Qt QML TableView Header not displaying [duplicate]

I am creating a Table using the new qml tableview (Qt 5.12).
I am able to create a model in C++ and able to populate the model in tabular format along with scrollbar.How do I add column headers to this table?
Code:
import QtQuick 2.12
import QtQuick.Controls 2.5
import Qt.labs.qmlmodels 1.0
//import QtQuick.Controls.Styles 1.4
import TableModel 0.1
Rectangle {
id:table
border.width: 3
border.color: 'dark blue'
QtObject{
id:internals
property int rows:0
property int col:0
property int colwidth:0
property var columnName:[]
}
function setRows(num){ internals.rows = num}
function setCols(num){ internals.col = num}
function setColWidth(num){internals.colwidth = num}
function setColNames(stringlist){
if(stringlist.length > 1)
internals.col = stringlist.length
dataModel.setColumnName(stringlist);
}
function addRowData(stringlist){
var len = stringlist.length
if(len >0)
{
dataModel.addData(stringlist)
}
}
TableModel {
id:dataModel
}
TableView{
id:tbl
anchors.top: headerCell
anchors.fill: parent
//columnSpacing: 1
//rowSpacing: 1
clip: true
ScrollBar.horizontal: ScrollBar{}
ScrollBar.vertical: ScrollBar{}
model:dataModel
Component{
id:datacell
Rectangle {
implicitWidth: 100
implicitHeight: 20
color: 'white'
border.width: 1
border.color: 'dark grey'
Text {
id:txtbox
anchors.fill: parent
wrapMode: Text.NoWrap
clip: true
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: display
}
}
}
}
function init(){
console.log("Calling init")
tbl.delegate= datacell
}
}
Currently TableView does not have headers so you should create it, in this case use Row, Column and Repeater.
On the other hand you must implement the headerData method and you must do it Q_INVOKABLE.
class TableModel : public QAbstractTableModel
{
Q_OBJECT
public:
// ...
Q_INVOKABLE QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
// ...
TableView {
id: tableView
model: table_model
// ...
Row {
id: columnsHeader
y: tableView.contentY
z: 2
Repeater {
model: tableView.columns > 0 ? tableView.columns : 1
Label {
width: tableView.columnWidthProvider(modelData)
height: 35
text: table_model.headerData(modelData, Qt.Horizontal)
color: '#aaaaaa'
font.pixelSize: 15
padding: 10
verticalAlignment: Text.AlignVCenter
background: Rectangle { color: "#333333" }
}
}
}
Column {
id: rowsHeader
x: tableView.contentX
z: 2
Repeater {
model: tableView.rows > 0 ? tableView.rows : 1
Label {
width: 60
height: tableView.rowHeightProvider(modelData)
text: table_model.headerData(modelData, Qt.Vertical)
color: '#aaaaaa'
font.pixelSize: 15
padding: 10
verticalAlignment: Text.AlignVCenter
background: Rectangle { color: "#333333" }
}
}
}
The complete example you find here.
If you're using Qt 5.15, you can use a HorizontalHeaderView for column labels.
https://doc.qt.io/qt-5/qml-qtquick-controls2-horizontalheaderview.html
There's also VerticalHeaderView for row labeling.
https://doc.qt.io/qt-5/qml-qtquick-controls2-verticalheaderview.html
I'm new to the QML. I came to the answer of eyllanesc so many times through my struggle with the new TableView (qt 5.12+), so I wanna thank you and share what helped me even more.
It's this video:
Shawn Rutledge - TableView and DelegateChooser: new in Qt 5.12
part of Qt Virtual Tech Summit 2019
The discussed code
It's a bit long but he covers
the differences between old and new TableView
how to create universal model for the views
resizable headers
different representation per column type - DelegateChooser
sortable columns
column reorder

Access to existing QML component from C++

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

How to set ListView model from C++?

I want to create tab with ListView from C++. Part of adding tab is done :D I want to have one model per ListView and be able to control model from C++ side.
So far I have done this:
C++ part:
SmsModel *model = new SmsModel();
model->createDummyData(phoneNumber);
QObject* tab = findTab(phoneNumber);
if (tab == nullptr)
{
QObject* pRoot = mAppEngine->rootObjects()[0];
QObject* m_pTabView= pRoot->findChildren<QObject*>("conversationTabView").first();
if (m_pTabView)
{
QVariant returnedValue;
QVariant title = phoneNumber;
QQmlContext *context = new QQmlContext(mAppEngine, mAppEngine);
context->setContextProperty(QString("myModel"), model);
QQmlComponent *component = new QQmlComponent(mAppEngine, QUrl("qrc:/ChatView.qml"), this);
QObject *object = component->create(context);
QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
QObject *p = object->findChild<QObject*>("chatView");
p->setProperty("model", context->contextProperty("myModel"));
qDebug() << p->property("model");
object->setProperty("active", QVariant(true));
component->setParent(m_pTabView);
QMetaObject::invokeMethod(m_pTabView, "addTab",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, title),
Q_ARG(QVariant, QVariant::fromValue(component)));
object->setProperty("anchors.fill", "parent");
}
QML part:
import QtQuick 2.5
import QtQml.Models 2.2
import QtQuick.Window 2.2
import org.example 1.0
Rectangle {
color: "#E0E0E0"
ListView {
objectName: "chatView"
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
clip: true
model: myModel
delegate: bubbleDelegate
Component {
id: bubbleDelegate
Rectangle {
implicitWidth: messageText.implicitWidth + 2*messageText.anchors.margins
implicitHeight: messageText.implicitHeight + 2*messageText.anchors.margins
anchors.left: model.received ? parent.left : undefined
anchors.right: model.received ? undefined : parent.right
anchors.margins: 5
id: bubble
smooth: true
radius: 10
color: model.received ? "#673AB7" : "#E040FB"
Text {
id: messageText
anchors.fill: parent
anchors.margins: 5
text: model.message
wrapMode: Text.WordWrap;
horizontalAlignment: model.received ? Text.AlignLeft : Text.AlignRight
color: "white"
}
}
}
}
}
When I run my application, there is no data in GUI and I have following error
ReferenceError: myModel is not defined.
Thank you for every response.
In order to use a C++ object as a list model you must have a class that inherits from QAbstractListModel. Take a look at the example here.

QtQuick: QQmlApplicationEngine failed to load component qrc:/main.qml:23 Invalid attached object assignment

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 {
}
}