只能从 GUI 线程或 QQuickItem::updatePaintNode() 安排更新
Updates can only be scheduled from GUI thread or from QQuickItem::updatePaintNode()
我正在尝试使用带有 PyQt5 的 QML 更改存储在文件夹中的带按钮(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"
}
}
}
当我在 raspberry Pi 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()
我还尝试创建 class,方法是更改图像源 属性,然后在按下按钮时调用相同的方法(通过 Class 对象),但它显示相同的错误消息
有没有办法在 QML 中设置图像的 Source
属性 - 从 Python.
中的父线程
在 Winforms 中我们可以通过使用 Delegates
来避免 "Cross-Thread Violation Error"。
我们可以使用 Signal and Slot
来解决 PyQt5 中的这个问题吗?
gpiozero 使用线程来监视 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"
}
}
我正在尝试使用带有 PyQt5 的 QML 更改存储在文件夹中的带按钮(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"
}
}
}
当我在 raspberry Pi 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()
我还尝试创建 class,方法是更改图像源 属性,然后在按下按钮时调用相同的方法(通过 Class 对象),但它显示相同的错误消息
有没有办法在 QML 中设置图像的 Source
属性 - 从 Python.
在 Winforms 中我们可以通过使用 Delegates
来避免 "Cross-Thread Violation Error"。
我们可以使用 Signal and Slot
来解决 PyQt5 中的这个问题吗?
gpiozero 使用线程来监视 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"
}
}