SCP3008
SCP3008

Reputation: 145

Initialize and Customize QML Components with Python

Is there a way for me to treat QML components as objects, and initialize them in Python? For instance, here's a simplified QML for a box: I want to be able to replicate what a constructor method can do in Java. I want to be able to customize the text on each box through the Python script and also, at the same time, create multiple box instances that are separate from each other.

import QtQuick 2.0
import QtQuick.Controls 2.0

Item {
    id: boxItem
    width: 800
    height: 118

    Rectangle {

        id: boxRect
        height: 118
        color: "#55f555"
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.top: parent.top

        Text {
            id: textItem
            width: 463
            height: 43
            color: "#000000"
            text: qsTr("Header Text")
            anchors.left: parent.left
            anchors.top: parent.top
            font.pixelSize: 38
            verticalAlignment: Text.AlignVCenter
            font.family: "Roboto"
            textFormat: Text.AutoText
            anchors.leftMargin: 20
            anchors.topMargin: 20
        }
    }

}

This is my current Python script modified from Qt's template version:

import os
import sys
from pathlib import Path

import PySide6.QtQml
from PySide6.QtQuick import QQuickView
from PySide6.QtCore import Qt, QUrl
from PySide6.QtGui import QGuiApplication


if __name__ == '__main__':

    #Set up the application window
    app = QGuiApplication(sys.argv)
    view = QQuickView()
    view.setResizeMode(QQuickView.SizeRootObjectToView)

    #Load the QML file
    qml_file = Path(__file__).parent / "Main.qml"
    view.setSource(QUrl.fromLocalFile(os.fspath(qml_file.resolve())))

    #Show the window
    if view.status() == QQuickView.Error:
        sys.exit(-1)
    view.show()

    #execute and cleanup
    app.exec()
    del view

Quick clarification: I am working with custom built QML components, not trying to edit pre-existing ones made by QT.

Upvotes: 1

Views: 744

Answers (1)

eyllanesc
eyllanesc

Reputation: 244311

Applying the concepts of another technology (programming language, library, framework) are often a bad approach to use some other technology. Each technology has its own methodology and good practices to implement any requirement.

In the case of QML the other languages such as C++, python, etc. are generally considered to implement business logic (something like a backend) and QML takes care of the view and the operation. In this case, it is recommended to create a QObject that provides other QObjects that create, modify, etc. the data and this can be reflected in the view. In this particular case, for the requirement, it is enough to use a model and a custom qml Item.

Box.qml

import QtQuick 2.0
import QtQuick.Controls 2.0

Item {
    id: boxItem
    width: 800
    height: 118

    property alias text: textItem.text

    Rectangle {

        id: boxRect
        height: 118
        color: "#55f555"
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.top: parent.top

        Text {
            id: textItem
            width: 463
            height: 43
            color: "#000000"
            anchors.left: parent.left
            anchors.top: parent.top
            font.pixelSize: 38
            verticalAlignment: Text.AlignVCenter
            font.family: "Roboto"
            textFormat: Text.AutoText
            anchors.leftMargin: 20
            anchors.topMargin: 20
        }
    }
}

main.qml

import QtQuick 2.0
import QtQuick.Controls 2.0

Item {
    id: root
    ScrollView 
    {
        anchors.fill: parent
        Column{
            Repeater{
                model: manager.model
                Box{
                    text: model.display
                }
            }
        }
    }
}

main.py

import os
import sys
from pathlib import Path


from PySide6.QtCore import Property, QObject, Qt, QUrl
from PySide6.QtGui import QGuiApplication, QStandardItemModel, QStandardItem
from PySide6.QtQuick import QQuickView


class Manager(QObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._model = QStandardItemModel()

    @Property(QObject, constant=True)
    def model(self):
        return self._model


if __name__ == "__main__":

    # Set up the application window
    app = QGuiApplication(sys.argv)
    view = QQuickView()
    view.setResizeMode(QQuickView.SizeRootObjectToView)

    manager = Manager()
    view.rootContext().setContextProperty("manager", manager)

    qml_file = Path(__file__).parent / "main.qml"
    view.setSource(QUrl.fromLocalFile(os.fspath(qml_file.resolve())))

    if view.status() == QQuickView.Error:
        sys.exit(-1)
    view.resize(640, 480)
    view.show()

    for i in range(20):
        item = QStandardItem(f"item-{i}")
        manager.model.appendRow(item)

    app.exec()

Upvotes: 2

Related Questions