Issue
Here is the main.py script:
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()
Next follows the 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()}
}*/
}
The two triangles when I start the program are shown very nice. The trouble appears when I click the button. I tried all sorts of variants to indent the modify_Polygons() function inside the GG class. In every version I received the same error: Property 'modify_Polygons' of object GG(0x103056bd0) is not a function comming from the Demo01.qml -> row 30. I don't have any clue why this error appears because for me looks like a legitimate function.
What did I make wrong, please?
Solution
Only the elements of the QMetaObject are accessible from QML like the qproperties, signals and slots, and the other elements of the class are not visible from QML. So one solution is to use the @pyqtSlot decor.
On the other hand you should not use time.sleep as it will block the main thread and consequently freeze the GUI. If you want to do periodic tasks then use a QTimer.
@pyqtSlot()
def modify_Polygons(self) -> None:
for x in range(10):
# time.sleep(1)
GG.set_dynamic_polygons(x, self)
On the other hand, if you want to make animations (even if you only indicate it in the title of your post) then you must use 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)
Answered By - eyllanesc
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.