有几种方法可以从python / C ++修改QML元素的属性,每种方法都有其优点和缺点。
1.从QML中提取引用
- 通过findChildren通过另一个对象获取QML对象。
- 修改或访问属性与
setProperty()
或property()
分别或QQmlProperty。
main.qml ( qml 用于接下来的2个.py)
import QtQuick 2.11import QtQuick.Window 2.2import QtQuick.Controls 2.2ApplicationWindow { 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" }}1.1 setProperty(),property()。
import osimport sysfrom PyQt5 import QtCore, QtGui, QtQmlfrom functools import partialdef 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())1.2 QQmlProperty。
import osimport sysfrom PyQt5 import QtCore, QtGui, QtQmlfrom functools import partialdef 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知道的情况下将其消除,因此它将访问错误的引用,从而导致应用程序意外终止。
2.推送对QML的引用
- 创建具有相同类型的属性的QObject。
- 使用setContextProperty导出到QML。
- 在QObject的属性和项目的属性之间进行绑定。
main.qml
import QtQuick 2.11import QtQuick.Window 2.2import QtQuick.Controls 2.2ApplicationWindow { 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 osimport sysfrom PyQt5 import QtCore, QtGui, QtQmlfrom functools import partialclass 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,依赖项不存在。
因此,我更喜欢使用第二种方法,有关更多信息,请阅读C ++中的与QML交互。



