从python在QML中的画布上动画元素

阿米尼克斯

这是main.py脚本:

import sys, os, math
import numpy as np
import time
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):
    polygonsChanged = pyqtSignal()

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

    def modify_Polygons(self) -> None:
        for x in range(10):
            time.sleep(1)
            GG.set_dynamic_polygons(x, self)

    def get_polygons(self) -> None:
        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
    )

    def set_dynamic_polygons(i, p_gg) -> None:

        numpy_arrays = np.array(
            [[[100+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()
        ROOT_DIR = os.path.realpath(os.path.dirname(sys.argv[0]))

        qml = os.path.join(ROOT_DIR, "QML Files", "Demo01.qml")
        view.setSource(QUrl.fromLocalFile(qml))

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

        view.setResizeMode(QQuickWidget.SizeRootObjectToView)
        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
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: "Click Me"
            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(){ drawingCanvas.requestPaint()}
         }*/

    }

当我启动程序时,两个三角形显示得非常好。单击按钮时出现问题。我尝试了各种变体来缩进GG类中Modify_Polygons()函数。在每个版本中,我都会收到相同的错误:对象GG(0x103056bd0)的属性'modify_Polygons'不是来自Demo01.qml- >第30行的函数。我不知道出现此错误的任何线索,因为对我来说合法功能。

请问我做错了什么?

永乐

从QML仅可以访问QMetaObject的元素,例如qproperties,信号和插槽,而从QML看不到该类的其他元素。因此,一种解决方案是使用@pyqtSlot装饰。

另一方面,您不应该使用time.sleep,因为它将阻塞主线程并因此冻结GUI。如果要执行定期任务,请使用QTimer。

@pyqtSlot()
def modify_Polygons(self) -> None:
    for x in range(10):
        # time.sleep(1)
        GG.set_dynamic_polygons(x, self)

另一方面,如果要制作动画(即使仅在帖子标题中指明),则必须使用QVariantAnimation:

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章