setContextProperty() 不会在 qml 文件中创建类实例

Posted

技术标签:

【中文标题】setContextProperty() 不会在 qml 文件中创建类实例【英文标题】:setContextProperty() doesn't create the class instance inside the qml file 【发布时间】:2020-12-05 06:23:25 【问题描述】:

main.py 文件显示一个选项卡小部件。在每个选项卡上,我加载了一个特定的 qml 文件,但为了这个问题,我将只考虑一个 qml 文件和一个选项卡:

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()

现在是 Demo01.qml 文件:

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()
        
       
    

问题是没有实例化qml文件里面的gg,声称gg对象为null。所以不在我的画布上画任何东西。 我尝试使用 QQuickWidgetQQuickView 并得到相同的 null 结果。 如您所见,qml 页面加载到 Tab 窗口没有任何问题。

如果不适用于上述两个元素,如何设置上下文。

【问题讨论】:

【参考方案1】:

您的问题有 2 个错误:

您必须在加载 .qml 之前设置上下文属性。 “gg”是一个局部变量,一旦构造函数执行完毕就被销毁,所以在qml中它会为null,解决方案是延长生命周期,例如将其作为类的属性。李>
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)

【讨论】:

谢谢。您的解决方案有效。我会认为这个问题已经结束。

以上是关于setContextProperty() 不会在 qml 文件中创建类实例的主要内容,如果未能解决你的问题,请参考以下文章

使用组件未找到 Qt 文件

如何将 QVariant::fromValue 与 QString 一起使用?

Pyside2:使用属性更新 QML TableView 模型

如何在 QML 中访问基于 QObjectList 的模型中的某些元素

获取当前上下文以设置对象列表模型

使用 Python 从 QML 中动态创建的列表中访问数据