为了账号安全,请及时绑定邮箱和手机立即绑定

如何从我的 Python 文件更新 Qml 对象的属性?

如何从我的 Python 文件更新 Qml 对象的属性?

紫衣仙女 2021-11-09 14:35:23
我想在 Qml 中显示一个矩形,并且我想从我的 Python 代码中更改矩形的属性(宽度、长度)。其实python代码中有一个socket连接,通过这个socket连接从另一台电脑接收width和length的值。简单来说:另一个用户应该能够实时调整这个矩形。我知道如何在我的 python 文件中建立套接字连接并使用 PyQt5,我可以从 python 显示 qml 文件。但是,我无法通过我的 python 代码访问矩形的参数。我怎样才能做到这一点?这是我的 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: 200        height: 200        color: "blue"    }}这是我在 .py 文件中写的内容:from PyQt5.QtQml import QQmlApplicationEngine, QQmlPropertyfrom PyQt5.QtQuick import QQuickWindow, QQuickViewfrom PyQt5.QtCore import QObject, QUrlfrom PyQt5.QtWidgets import QApplicationimport sysdef 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())
查看完整描述

2 回答

?
慕尼黑5688855

TA贡献1848条经验 获得超2个赞

有几种方法可以从 python/C++ 修改 QML 元素的属性,每种方法都有其优点和缺点。

1. 从 QML 中提取引用

  • 通过另一个对象通过 findChildren 获取 QML 对象。

  • 修改或访问属性与setProperty()property()分别或QQmlProperty。


main.qmlqml用于接下来的 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"

    }

}

1.1 setProperty()、property()。

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

1.2 QQml属性。

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 不知道的情况下被消除,因此它会访问不正确的引用,从而导致应用程序意外终止。

2. 推送对 QML 的引用

  • 创建一个具有相同类型属性的 QObject。

  • 使用 setContextProperty 导出到 QML。

  • 在 QObject 的属性和项目的属性之间进行绑定。


主文件

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

缺点是您必须编写更多代码。优点是对象可以被所有 QML 访问,因为它使用了 setContextProperty,另一个优点是如果 QML 对象被删除,它不会产生问题,因为只消除了绑定。最后,通过不使用 objectName,依赖项不存在。


所以我更喜欢使用第二种方法,有关更多信息,请阅读Interacting with QML from C++




查看完整回答
反对 回复 2021-11-09
?
富国沪深

TA贡献1790条经验 获得超9个赞

尝试以下操作(未测试,但会给您一个想法)。


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)  


查看完整回答
反对 回复 2021-11-09
  • 2 回答
  • 0 关注
  • 174 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号