从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_Polgons((函数。在每个版本中,我都收到了相同的错误:对象GG(0x103056bd0(的属性"modify_Polgons"不是Demo01.qml->第30行。我不知道为什么会出现这个错误,因为对我来说,这看起来是一个合法的函数。

请问我做错了什么?

只有QMetaObject的元素可以从QML访问,如qproperty、信号和槽,该类的其他元素在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)

最新更新