Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
164 views
in Technique[技术] by (71.8m points)

python - setContextProperty() doesn't create the class instance inside the qml file

The main.py file displays a Tab Widget. On each Tab I loaded a speciffic qml file but for the sake of this question I will consider only one qml file and one single tab:

import sys, os, math
import numpy as np
from PyQt5 import *

class Tab(QFrame):
    def __init__(self):
        super().__init__()
        self.setGeometry(600, 600, 600, 600)
        self.setWindowTitle("PyQt5 Tab Widget")
       
        vbox = QVBoxLayout()
        tabWidget = QTabWidget()

        tabWidget.addTab(Example01(), "Ex1")
        
        vbox.addWidget(tabWidget)
        self.setLayout(vbox)

class GG(QObject):
    polygonsChanged = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self._polygons = []
    def get_polygons(self):
        return self._polygons

    def set_polygons(self, polygons):
        self._polygons = polygons
        self.polygonsChanged.emit()

    polygons = pyqtProperty(
        "QVariant", fget=get_polygons, fset=set_polygons,
        notify=polygonsChanged
    )


class Example01(QWidget):

    def __init__(self):
        super().__init__()
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)


        numpy_arrays = np.array(
            [[[100, 100], [150, 200], [50, 300]],
             [[50, 60], [160, 10], [400, 0]]]
        )

        polygons = []
        for ps in numpy_arrays:
            polygon = []
            for p in ps:
                e = QPointF(*p)
                polygon.append(e)
            polygons.append(polygon)

        gg = GG()
        gg.polygons = polygons
        print(gg.polygons)

        ROOT_DIR = os.path.realpath(os.path.dirname(sys.argv[0]))
        # print(ROOT_DIR)

        qml = os.path.join(ROOT_DIR, "QML Files", "Demo01.qml")

        view = QQuickWidget()

        view.setSource(QUrl.fromLocalFile(qml))

        view.rootContext().setContextProperty("gg", gg)

        view.setResizeMode(QQuickWidget.SizeRootObjectToView)
        # widget = QWidget.createWindowContainer(view)
        # vbox.addWidget(widget)

        vbox.addWidget(view)


if __name__ == "__main__":
    App = QApplication(sys.argv)
    tabDialog = Tab()
    tabDialog.show()
    App.exec()

Now the Demo01.qml file:

import QtQuick 2.14
import QtQuick.Window 2.14
import QtGraphicalEffects 1.0


Rectangle {
    id: rect

        visible: true
        anchors.fill: parent

        LinearGradient {
                anchors.fill: parent
                //setting gradient at 45 degrees
                start: Qt.point(rect.width, 0)
                end: Qt.point(0, rect.height)
                gradient: Gradient {
                    GradientStop { position: 0.0; color: "#ee9d9d" }
                    GradientStop { position: 1.0; color: "#950707" }
                }
            }

        Canvas {
            id: drawingCanvas
            anchors.fill: parent
            onPaint: {
                var ctx = getContext("2d")
                ctx.lineWidth = 5;
                ctx.strokeStyle = "red"
                console.log(gg)
                for(var i in gg.polygons){
                    var polygon = gg.polygons[i]
                    ctx.beginPath()
                    for(var j in polygon){
                        var p = polygon[j]
                        if(j === 0)
                            ctx.moveTo(p.x, p.y)
                        else
                            ctx.lineTo(p.x, p.y)
                    }
                    ctx.closePath()
                    ctx.stroke()
                }
            }
           
        }
       
       Connections{
            target: gg
            function onPolygonsChanged(){ drawingCanvas.requestPaint()}
        }
       
    }

The problem is that does not instantiate the gg inside the qml file, claiming that the gg object is null. So does not draw anything on my canvas. I tried with QQuickWidgetand with QQuickView and had the same null result. As you can see the qml page is loaded on the Tab window without any problem.

How can be set the context thou, if doesn't work with the two mentioned elements.

question from:https://stackoverflow.com/questions/65926511/setting-connections-and-signal-targets-using-qml-to-python

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your problem has 2 errors:

  • You have to set the context property before loading the .qml.
  • "gg" is a local variable that is destroyed as soon as the constructor finishes executing, so in qml it will be null, the solution is to extend the life cycle for example by making it an attribute of the class.
class Example01(QWidget):
    def __init__(self):
        super().__init__()
        numpy_arrays = np.array(
            [[[100, 100], [150, 200], [50, 300]], [[50, 60], [160, 10], [400, 0]]]
        )

        polygons = []
        for ps in numpy_arrays:
            polygon = []
            for p in ps:
                e = QPointF(*p)
                polygon.append(e)
            polygons.append(polygon)

        self.gg = GG()
        self.gg.polygons = polygons
        ROOT_DIR = os.path.realpath(os.path.dirname(sys.argv[0]))
        qml = os.path.join(ROOT_DIR, "QML Files", "Demo01.qml")

        view = QQuickWidget()
        view.rootContext().setContextProperty("gg", self.gg)
        view.setSource(QUrl.fromLocalFile(qml))
        view.setResizeMode(QQuickWidget.SizeRootObjectToView)

        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.addWidget(view)

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...