QML - .qml 文件中的“连接”不会触发来自 python 脚本的信号

Posted

技术标签:

【中文标题】QML - .qml 文件中的“连接”不会触发来自 python 脚本的信号【英文标题】:QML - The "Connections" from .qml file doesn't fire the signal from python script 【发布时间】:2020-12-16 01:26:29 【问题描述】:

这是 main.py 脚本:

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")
        self.setWindowIcon(QIcon("../QML Files/Icons/Tab.png"))

        vbox = QVBoxLayout()
        tabWidget = QTabWidget()

        tabWidget.addTab(Example01(), "Ex1")
       

        vbox.addWidget(tabWidget)
        self.setLayout(vbox)


class GG(QObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._polygons = []

    @pyqtSlot()
    def modify_Polygons(self) -> None:
        animation = QVariantAnimation(self)
        animation.setStartValue(0)
        animation.setEndValue(10)
        animation.valueChanged.connect(
            lambda value: GG.set_dynamic_polygons(value, self)
        )
        animation.setDuration(10 * 1000)
        animation.start(QAbstractAnimation.DeleteWhenStopped)

    polygonschanged = pyqtSignal(str)

    def get_polygons(self) -> None:
        return self._polygons

    def set_polygons(self, polygons):
        self._polygons = polygons
        self.polygonschanged.emit("Test")

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

    def set_dynamic_polygons(i, p_gg) -> None:

        numpy_arrays = np.array(
            [[[100+3*i, 100], [150, 200], [50, 300]],
             [[50, 60], [160, 20], [400, 10]]]
        )

        def set_polygons(myArray) -> []:
            polygons = []
            for ps in myArray:
                polygon = []
                # print("ps = "); print(ps)
                for p in ps:
                    # print("p = "); print(p)
                    e = QPointF(*p)
                    polygon.append(e)
                polygons.append(polygon)
            return polygons

        p_gg.polygons = set_polygons(numpy_arrays)


class Example01(QWidget):
    def __init__(self):
        super().__init__()
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        self.gg = GG()
        GG.set_dynamic_polygons(0, self.gg)

        view = QQuickWidget()
        view.rootContext().setContextProperty("gg", self.gg)

        ROOT_DIR = os.path.realpath(os.path.dirname(sys.argv[0]))
        qml = os.path.join(ROOT_DIR, "QML Files", "Demo02.qml")
        view.setSource(QUrl.fromLocalFile(qml))
        view.setResizeMode(QQuickWidget.SizeRootObjectToView)
        vbox.addWidget(view)

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

这是 Demo02.qml 脚本:

import QtQuick 2.14
import QtQuick.Window 2.14
import QtGraphicalEffects 1.0
import QtQuick.Controls 2.15


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" 
                
            
        Button
            id: btn
            width: 100
            height: 30
            x: parent.width - btn.width - 20
            y: parent.height - btn.height - 20
            text: "Animate!"
            onClicked: gg.modify_Polygons()
        

        Canvas 
            id: drawingCanvas
            anchors.fill: parent
            
            onPaint: 
                var ctx = getContext("2d")
                ctx.fillStyle = "rgb(100%,70%,30%)"
                ctx.lineWidth = 5
                ctx.strokeStyle = "blue"
                //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.fill()
                    ctx.stroke()
                

            
            Connections
                 target: gg
                 function onpolygonschanged(strng)
                     console.log(strng)
                     drawingCanvas.requestPaint()
             
        



    

除了 Demo02.qml 文件末尾的 Connections 指令并没有真正调用 polygonschanged 之外,一切运行正常来自 python 的信号。 我刚刚插入了console.log("Test") 来检查是否发出信号以便被.qml 文件看到,但我没有收到任何反应。 我不得不提一下,画布最初显示了 2 个三角形,但是当我单击“激活!”时按钮画布显示相同的三角形,但不对其进行动画处理。 有人可以建议如何正确设置 .qml 文件中的“连接”吗?

【问题讨论】:

【参考方案1】:

在qml中与信号关联的函数名必须是CamelCase,即:

Connections
    target: gg
    function onPolygonsChanged(strng)
        console.log(strng)
        drawingCanvas.requestPaint()
    

【讨论】:

是的。它正在工作。感谢您的回答。

以上是关于QML - .qml 文件中的“连接”不会触发来自 python 脚本的信号的主要内容,如果未能解决你的问题,请参考以下文章

绑定来自两个不同 qml 文件的两个元素

来自 C++ 插件的 QML 类型仅发出一次信号

在 Component.onCompleted 之前初始化 QML 信号

QML 图像不会在图像源中加载具有非 ASCII 字符的图像

Qt QML包含来自不同目录的问题

QML 中的堆栈布局