【问题标题】:Updates can only be scheduled from GUI thread or from QQuickItem::updatePaintNode()只能从 GUI 线程或 QQuickItem::updatePaintNode() 安排更新
【发布时间】:2020-04-27 21:56:45
【问题描述】:

我正在尝试使用 QML 和 PyQt5 更改存储在文件夹中的按钮 (GPIO PIN) 的图像
Python代码:

from gpiozero import Button
from signal import pause

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtQml import *
import os, time, sys


def btn_pressed():
    global r
    return lambda: r.setProperty("source", "/home/pi/Desktop/example/sample/img/img1.jpg")

button1 = Button(20)        
myApp = QGuiApplication([])
myEngine = QQmlApplicationEngine()
directory = os.path.dirname(os.path.abspath(__file__))
myEngine.load(QUrl.fromLocalFile(os.path.join(directory, 'simple1.qml')))
if not myEngine.rootObjects():
    print("root object not found")

r = myEngine.rootObjects()[0].findChild(QObject, "DisplayImage")
dir(r)
print("Main Thead id ",myApp.thread())
updateUI = UpdateUI()

button1.when_pressed = btn_pressed()   
myEngine.quit.connect(myApp.quit)
sys.exit(myApp.exec_())

QML:

import QtQuick 2.10
import QtQuick.Controls 1.6
import QtQuick.Window 2.2

ApplicationWindow {
    id : main
    title: qsTr("Test")
    width: 640
    height: 480
    visible: true

    Rectangle{
        width: parent.width
        height: parent.height

        Image {
            id: img
            source: ""
            width : main.width;
            fillMode : Image.PreserveAspectFit
            objectName: "DisplayImage"
        }
    }
}

当我在树莓派 4 中按下连接到 GPIO 20 的按钮时,我收到以下错误消息。

QObject: Cannot create children for a parent that is in a different thread. 
(Parent is QQmlApplicationEngine(0x10f5ba0), parent's thread is QThread(0xf6f7c0), current thread is QThread(0xa98007c8)
Updates can only be scheduled from GUI thread or from QQuickItem::updatePaintNode()

我还尝试使用更改图像源属性的方法创建类,然后在按下按钮时调用相同的方法(通过类对象),但它显示相同的错误消息

有没有办法在 QML 中设置 Image 的 Source 属性 - 从 Python 中的父线程。

在 Winforms 中,我们可以通过使用 Delegates 来避免“跨线程冲突错误”。

我们可以使用Signal and Slot 在 PyQt5 中解决这个问题吗?

【问题讨论】:

    标签: python pyqt qml pyqt5 gpiozero


    【解决方案1】:

    使用线程来监控 gpio 以免阻塞主 GUI,因此相关函数 when_pressed 将在该线程中执行,但 Qt 禁止从另一个线程更新 GUI 元素,例如图像。

    解决方案是创建一个 QObject,它在与 when_pressed 关联的方法中发出信号,因为信号是线程安全的。

    另一方面,从 C++/Python 修改 QML 元素并不好,最好将 QObject 导出到 QML 并在该范围内建立连接。

    import os
    import sys
    
    from gpiozero import Button
    
    from PyQt5.QtCore import pyqtSignal, QObject, QUrl
    from PyQt5.QtGui import QGuiApplication
    from PyQt5.QtQml import QQmlApplicationEngine
    
    
    class ButtonManager(QObject):
        pressed = pyqtSignal()
    
        def __init__(self, parent=None):
            super().__init__(parent)
            self._button = Button(20)
            self._button.when_pressed = self._on_when_pressed
    
        def _on_when_pressed(self):
            self.pressed.emit()
    
    
    if __name__ == "__main__":
        app = QGuiApplication(sys.argv)
        button_manager = ButtonManager()
        engine = QQmlApplicationEngine()
        engine.rootContext().setContextProperty("button_manager", button_manager)
        current_dir = os.path.dirname(os.path.abspath(__file__))
        engine.load(QUrl.fromLocalFile(os.path.join(current_dir, "simple1.qml")))
        if not engine.rootObjects():
            print("root object not found")
            sys.exit(-1)
        engine.quit.connect(app.quit)
        sys.exit(app.exec_())
    

    simple1.qml

    import QtQuick 2.10
    import QtQuick.Controls 1.6
    import QtQuick.Window 2.2
    
    ApplicationWindow {
        id : main
        title: qsTr("Test")
        width: 640
        height: 480
        visible: true
        Rectangle{
            anchors.fill: parent
            Image {
                id: img 
                width : main.width
                fillMode : Image.PreserveAspectFit
            }
        }
        Connections{
            target: button_manager
            onPressed: img.source = "/home/pi/Desktop/example/sample/img/img1.jpg"
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-10
      • 2010-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多