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

2024-02-29

我想在 Qml 中显示一个矩形,并且想从我的 python 代码中更改矩形的属性(宽度、长度)。实际上,Python代码中有一个套接字连接,通过该连接从另一台计算机接收宽度和长度的值。简单地说:另一个用户应该能够实时调整这个矩形。 我知道如何在 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())

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

1. 从 QML 中提取引用

  • 通过另一个对象通过findChildren获取QML对象。
  • Modify or access the property with setProperty() or property(), respectively or with 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"
    }
}

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

这种方法的缺点是,如果对象与根对象的关系很复杂(有时很难使用 findChild 访问其他 QML 中的对象),则访问对象的部分会变得复杂,有时甚至是不可能的,因此此方法将失败。另一个问题是,当使用 objectName 作为主要搜索数据时,Python 层对 QML 层具有高度依赖性,因为如果在 QML 中修改 objectName,则必须修改 python 中的逻辑。另一个缺点是,如果不管理 QML 对象的生命周期,它可能会在 Python 不知情的情况下被消除,因此它会访问不正确的引用,导致应用程序意外终止。

2. 推送对 QML 的引用

  • 创建一个具有相同类型属性的 QObject。
  • 使用 setContextProperty 导出到 QML。
  • 在 QObject 的属性和项目的属性之间进行绑定。

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

缺点是需要多写一些代码。优点是该对象可以被所有 QML 访问,因为它使用 setContextProperty,另一个优点是如果 QML 对象被删除,它不会产生问题,因为仅消除了绑定。最后,通过不使用 objectName,依赖性不存在。


所以我更喜欢使用第二种方法,有关更多信息,请阅读从 C++ 与 QML 交互 https://doc.qt.io/qt-5/qtquick-bestpractices.html#interacting-with-qml-from-c.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从 Python 文件更新 Qml 对象的属性? 的相关文章

随机推荐

  • 如何获取 MongoDB 中的所有文档 ID?

    如何获取 MongoDB 中所有文档 ID 的数组 我只需要一组 id 但不需要文档内容 您可以通过调用在 Mongo shell 中执行此操作map http docs mongodb org manual reference metho
  • 为 MVC 应用程序添加尾部斜杠

    我正在构建一个基于 MVC 设计模式的应用程序 我希望我的 URL 如下 http example com page action http example com page action 我成功地让它与下面的代码一起工作 但如果 URL
  • 如果我要将文件内容读入数组,是否需要初始化数组?

    我正在初始化buf在立即用以下内容重写其内容之前不必要地全为零read exact fn parse
  • 在 Python 代码中使用 Git 命令

    我被要求编写一个脚本 从 Git 中提取最新代码 进行构建并执行一些自动化单元测试 我发现有两个内置的 Python 模块可以随时使用 用于与 Git 交互 GitPython and libgit2 我应该使用什么方法 模块 更简单的解决
  • 在输入类型=“文本”中键入时跟踪 onchange 的最佳方法?

    在我的经验中 input type text onchange事件通常仅在您离开后发生 blur 控制 有没有办法强制浏览器触发onchange每次textfield内容变化 如果不是 那么 手动 跟踪这个最优雅的方法是什么 Using o
  • 在 Razor 中将视图模型属性编码为 JavaScript

    我有一个简单的视图模型 public class IndexViewModel public bool ShowWelcomeMsg get set 在我看来 我需要 JS 中的这个属性 但这是不正确的 因为它输出False代替false但
  • 使用PyQt5嵌入动态条形图

    我在 python 中编写了以下代码 以在生成的 GUI 中显示条形图PyQt5 import sys from PyQt5 QtWidgets import QDialog QApplication QPushButton QVBoxLa
  • Libgdx ModelBuilder.createRect 仅从一侧可见

    在我的第一个 libgdx 3D 游戏中 我现在从createBox to createRect 仅创建可见面 如果一堵墙位于另一堵墙的左侧 则其右面不可见 我正在创建 4 个模型 frontFace backFace rightFace
  • 如何在React-native ListView中过滤数据?

    我正在尝试过滤数组对象列表 然后尝试使用新的数据源在 ListView 中显示 但是 该列表并未被过滤 我知道我的过滤功能工作正常 我在console log中检查过 我正在使用 Redux 将状态映射到 prop 然后尝试过滤道具 这是错
  • SignalR 和序列化对象数组

    我是 SignalR 的新手 并且已经完成了一个简单的测试 hack 我希望用类型化对象序列化对象数组 默认情况下 SignalR 已将 Json NET 序列化器配置为不提供类型信息 我发现我可以通过以下方式在 DependencyRes
  • 无法执行操作。计算替代解决方案,可能需要一段时间 STS?

    我想问一下添加新的时候出现这个错误是什么意思Available Software Site并使用 Eclipse STS Spring Tool Suite 安装新软件Install New Software 我遇到这个问题Spring T
  • 使用 new(Integer) 与 int

    在我的 Java 课上 教授使用了类似的内容 integerBox add new Integer 10 这和刚刚做的一样吗 integerBox add 10 我用谷歌搜索了一下 但找不到一种方法或另一种方法 而且教授也很含糊 我能找到的
  • 查找特殊字符之间的文本并替换字符串

    例如我有一个字符串包含 String s test string 67 Hi 我想得到这个字符串 67 有了星星 我就可以开始替换那部分字符串了 我现在的代码如下所示 String s test string 67 Hi s s subst
  • 如何拦截和抑制 TFrame 子组件的消息?

    我需要拦截WM PASTE message https stackoverflow com questions 10158861 how to intercept detect a paste command into a tmemo 10
  • Java/JSP WEB-INF/类无法导入

    自从我不得不做一些 Java JSP 以来已经有一段时间了 我在 WEB INF classes MyClass java 中有一个 java 类 Netbeans 中的构建成功 我可以在类文件夹中看到 MyClass class 在我的j
  • MariaDB Connector/Python 需要 MariaDB Connector/C >= 3.2.4,发现版本 3.1.14

    Ubuntu 20 04 需要版本 3 2 4 否则 pip3 install mariadb 是不可能的 pip3 install mariadb gt Collecting mariadb Using cached mariadb 1
  • 摇动后停止 Android 加速计

    我想听一下摇晃声 然后完全停止加速度计并转到另一项活动 遗憾的是我没有找到任何方法来做到这一点 即使我计算一个变量并使用简单的 如果 进行检查 每次检测到震动时它总是会再次加载新的活动 请帮助我解决我的不理解 Override protec
  • 加权随机图

    假设我有一个大的二维数组 其值范围在 0 1 范围内 其中 0 表示 不可能 1 表示 极有可能 如何根据上述概率在该数组中选择一组随机点 看待问题的一种方法是 暂时 忽略您正在处理二维网格的事实 你拥有的是一组加权的项目 从这样的集合中随
  • 有没有办法使用 JQuery GetJSON 方法从外部页面获取 HTML?

    假设您正在尝试执行 jquery ajax 请求 例如 ajax url http other website com 据我了解 由于同源原则 这个请求会失败 因为URL是外部域 不过我听说过GetJSON 不遵守此原则 可以使用 JSON
  • 如何从 Python 文件更新 Qml 对象的属性?

    我想在 Qml 中显示一个矩形 并且想从我的 python 代码中更改矩形的属性 宽度 长度 实际上 Python代码中有一个套接字连接 通过该连接从另一台计算机接收宽度和长度的值 简单地说 另一个用户应该能够实时调整这个矩形 我知道如何在