我想在Qml中显示一个矩形,并且想从我的python代码中更改矩形的属性(宽度,长度)。实际上,在python代码中有一个套接字连接,通过该套接字连接可以从另一台计算机接收width和length的值。简而言之:另一个用户应该能够实时调整此矩形。 我知道如何在python文件中建立套接字连接,并使用PyQt5,可以显示python中的qml文件。
但是,我在通过python代码访问矩形的参数时遇到了麻烦。我该怎么办?
这是我的qml文件的简化示例:
import QtQuick 2.11
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
ApplicationWindow {
visible: true
width: Screen.width/2
height: Screen.height/2
Rectangle {
id: rectangle
x: 187
y: 92
width: 200
height: 200
color: "blue"
}
}
这是我在.py文件中写的内容:
from PyQt5.QtQml import QQmlApplicationEngine, QQmlProperty
from PyQt5.QtQuick import QQuickWindow, QQuickView
from PyQt5.QtCore import QObject, QUrl
from PyQt5.QtWidgets import QApplication
import sys
def run():
myApp = QApplication(sys.argv)
myEngine = QQmlApplicationEngine()
myEngine.load('mainViewofHoomanApp.qml')
if not myEngine.rootObjects():
return -1
return myApp.exec_()
if __name__ == "__main__":
sys.exit(run())
答案 0 :(得分:2)
有几种方法可以从python / C ++修改QML元素的属性,每种方法都有其优缺点。
setProperty()
或property()
或使用QQmlProperty修改或访问该属性。
main.qml (该qml用于接下来的2个.py)
import QtQuick 2.11
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
ApplicationWindow {
visible: true
width: Screen.width/2
height: Screen.height/2
Rectangle {
id: rectangle
x: 187
y: 92
width: 200
height: 200
color: "blue"
objectName: "foo_object"
}
}
import os
import sys
from PyQt5 import QtCore, QtGui, QtQml
from functools import partial
def testing(r):
import random
w = r.property("width")
h = r.property("height")
print("width: {}, height: {}".format(w, h))
r.setProperty("width", random.randint(100, 400))
r.setProperty("height", random.randint(100, 400))
def run():
myApp = QtGui.QGuiApplication(sys.argv)
myEngine = QtQml.QQmlApplicationEngine()
directory = os.path.dirname(os.path.abspath(__file__))
myEngine.load(QtCore.QUrl.fromLocalFile(os.path.join(directory, 'main.qml')))
if not myEngine.rootObjects():
return -1
r = myEngine.rootObjects()[0].findChild(QtCore.QObject, "foo_object")
timer = QtCore.QTimer(interval=500)
timer.timeout.connect(partial(testing, r))
timer.start()
return myApp.exec_()
if __name__ == "__main__":
sys.exit(run())
import os
import sys
from PyQt5 import QtCore, QtGui, QtQml
from functools import partial
def testing(r):
import random
w_prop = QtQml.QQmlProperty(r, "width")
h_prop = QtQml.QQmlProperty(r, "height")
print("width: {}, height: {}".format(w_prop.read(), w_prop.read()))
w_prop.write(random.randint(100, 400))
h_prop.write(random.randint(100, 400))
def run():
myApp = QtGui.QGuiApplication(sys.argv)
myEngine = QtQml.QQmlApplicationEngine()
directory = os.path.dirname(os.path.abspath(__file__))
myEngine.load(QtCore.QUrl.fromLocalFile(os.path.join(directory, 'main.qml')))
if not myEngine.rootObjects():
return -1
r = myEngine.rootObjects()[0].findChild(QtCore.QObject, "foo_object")
timer = QtCore.QTimer(interval=500)
timer.timeout.connect(partial(testing, r))
timer.start()
return myApp.exec_()
if __name__ == "__main__":
sys.exit(run())
此方法的缺点是,如果对象与根对象的关系很复杂(有时其他QML中的对象很难用findChild访问),则访问对象的过程将变得复杂,有时甚至是不可能的,因此此方法将失败。另一个问题是,当使用objectName作为主要搜索数据时,Python层对QML层的依赖性很高,因为如果在QML中修改了ObjectName,则必须修改python中的逻辑。另一个缺点是,通过不管理QML对象的生命周期,可以在Python不知道的情况下将其消除,从而访问错误的引用,从而导致应用程序意外终止。
main.qml
import QtQuick 2.11
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
ApplicationWindow {
visible: true
width: Screen.width/2
height: Screen.height/2
Rectangle {
id: rectangle
x: 187
y: 92
width: r_manager.width
height: r_manager.height
color: "blue"
}
}
main.py
import os
import sys
from PyQt5 import QtCore, QtGui, QtQml
from functools import partial
class RectangleManager(QtCore.QObject):
widthChanged = QtCore.pyqtSignal(float)
heightChanged = QtCore.pyqtSignal(float)
def __init__(self, parent=None):
super(RectangleManager, self).__init__(parent)
self._width = 100
self._height = 100
@QtCore.pyqtProperty(float, notify=widthChanged)
def width(self):
return self._width
@width.setter
def width(self, w):
if self._width != w:
self._width = w
self.widthChanged.emit(w)
@QtCore.pyqtProperty(float, notify=heightChanged)
def height(self):
return self._height
@height.setter
def height(self, h):
if self._height != h:
self._height = h
self.heightChanged.emit(h)
def testing(r):
import random
print("width: {}, height: {}".format(r.width, r.height))
r.width = random.randint(100, 400)
r.height = random.randint(100, 400)
def run():
myApp = QtGui.QGuiApplication(sys.argv)
myEngine = QtQml.QQmlApplicationEngine()
manager = RectangleManager()
myEngine.rootContext().setContextProperty("r_manager", manager)
directory = os.path.dirname(os.path.abspath(__file__))
myEngine.load(QtCore.QUrl.fromLocalFile(os.path.join(directory, 'main.qml')))
if not myEngine.rootObjects():
return -1
timer = QtCore.QTimer(interval=500)
timer.timeout.connect(partial(testing, manager))
timer.start()
return myApp.exec_()
if __name__ == "__main__":
sys.exit(run())
缺点是您必须编写更多代码。优点是,由于该对象使用setContextProperty,因此所有QML都可以访问该对象,另一个优点是,如果删除了QML对象,则不会产生问题,因为仅消除了绑定。最后,通过不使用objectName,依赖项不存在。
因此,我更喜欢使用第二种方法,有关更多信息,请阅读Interacting with QML from C++。
答案 1 :(得分:0)
尝试以下类似方法(未经测试,但会给您一个想法)。
为矩形创建一些objectname
,如下所示:
Rectangle {
id: rectangle
x: 187
y: 92
width: 200
height: 200
color: "blue"
objectName: "myRect"
}
与QML交互并找到您的孩子,然后设置属性。
#INTERACT WITH QML
engine = QQmlEngine()
component = QQmlComponent(engine)
component.loadUrl(QUrl('mainViewofHoomanApp.qml'))
object = component.create()
#FIND YOUR RECTANGLE AND SET WIDTH
child = object.findChild(QObject,"myRect")
child.setProperty("width", 500)