信号未从线程传递到 GUI

Posted

技术标签:

【中文标题】信号未从线程传递到 GUI【英文标题】:Signals not passing from thread to GUI 【发布时间】:2017-09-29 07:08:13 【问题描述】:

此遥测程序从 USB 端口上的串行字符串中读取数据。 GUI 在 QML 文件中定义,读取串行端口由字符串处理。 GUI 加载并正常工作。 GUI 发送上的按钮有一个事件处理程序,它可以将信号发送回 GUI。这完美无缺。串行读取线程启动并正确运行。它读取并解析数据并将其打印到屏幕上。然而,信号并没有返回到 GUI。

这让我发疯了,谢谢你的帮助。

main.py

import sys
import serial
from io import StringIO
import csv
from openpyxl import Workbook
import datetime
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, QThread

global ser
#define and open the serial port
ser=serial.Serial('COM6')

class Dash(QObject):
    def __init__(self):
        QObject.__init__(self)

    ampHourvalue = pyqtSignal(int, arguments=['amphour'])


    @pyqtSlot(int)
    def reset(self, value):

        value=100  #put amp hour capacity here
        self.ampHourvalue.emit(value)

class ThreadClass(QThread):
    # Create the signal
    auxVoltage = pyqtSignal(str, arguments=['auxvolt'])
    mainVoltage = pyqtSignal(int, arguments=['mainvolt'])
    arrayCurrent = pyqtSignal(int, arguments=['arraycurrent'])
    motorCurrent = pyqtSignal(int, arguments=['motorcurrent'])


    def __init__(self, parent=None):
        super(ThreadClass, self).__init__(parent)

    def run(self):
        try:
            wb=load_workbook("History.xls") #attemps to open the history excel file
        except:
            wb=Workbook() #creates and empty excel workbook if histortory is not found

        WorkSheetName=datetime.date.today() #get todays date
        ws = wb.create_sheet("%s" %WorkSheetName) #create worksheet with the date as tittle

        while True:
            data=ser.readline(120) #read the stream
            print(data)
            data=data.decode() #convert stream from bytes to characters
            data=StringIO(data)#convert a stream of characters into string
            dataset=csv.reader(data, delimiter= ',') #read the CSV string into individual array
            dataset=list(dataset) #convert the array to list

            ws.append(dataset[0])
            wb.save("History.xls")

            #extract individual data points
            aux=dataset[0][1]
            print("Aux ", aux)
            mainvolt=dataset[0][2]
            print("Main ", mainvolt)
            arraycurrent=dataset[0][3]
            motorcurrent=dataset[0][4]

            # Emit the signals
            self.auxVoltage.emit(aux)
            self.mainVoltage.emit(mainvolt)
            self.arrayCurrent.emit(arraycurrent) 
            self.motorCurrent.emit(motorcurrent) 

            pass       


def main():
    import sys
    # Create an instance of the application
    app = QGuiApplication(sys.argv)

    #start the thread
    threadclass=ThreadClass()
    threadclass.start()


    # Create QML engine
    engine = QQmlApplicationEngine()
    # Create a Dash object
    dashboard = Dash()
    # And register it in the context of QML
    engine.rootContext().setContextProperty("dashboard", dashboard)
    # Load the qml file into the engine
    engine.load("take2.qml")

    engine.quit.connect(app.quit)
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

take2.qml

import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.2
import QtQuick.Extras 1.4


ApplicationWindow 
id: applicationWindow
visible: true
width: 1000
height: 500
color: "black"
title: "I like Telemetry"

Text 
    id: text1
    x: 300
    y: 6
    width: 353
    height: 34
    text: qsTr("Solar Car Telemetry System")
    anchors.horizontalCenter: parent.horizontalCenter
    horizontalAlignment: Text.AlignHCenter
    font.family: "Times New Roman"
    font.pixelSize: 30
    color: "grey"



CircularGauge 
    id: circularGauge
    x: 55
    y: 111
    width: 308
    height: 279
    anchors.verticalCenter: rowLayout.verticalCenter

    Text 
        id: text2
        x: 143
        y: 226
        text: qsTr("Speed")
        anchors.horizontalCenter: parent.horizontalCenter
        horizontalAlignment: Text.AlignHCenter
        font.pixelSize: 12
        color: "grey"
    


CircularGauge 
    id: auxvoltgauge
    x: 381
    y: 92
    width: 151
    height: 141
    stepSize: .5
    maximumValue: 15
    value:1


Text 
    id: text3
    x: 445
    width: 69
    text: qsTr("Aux Battery")
    anchors.top: parent.top
    anchors.topMargin: -17
    horizontalAlignment: Text.AlignHCenter
    anchors.horizontalCenter: parent.horizontalCenter
    font.pixelSize: 12
    color: "grey"


Text 
    id: text5
    x: 64
    y: 106
    text: qsTr("Volts")
    anchors.bottom: parent.bottom
    anchors.bottomMargin: 10
    font.pixelSize: 12
    color: "grey"



CircularGauge 
    id: circularGauge2
    x: 381
    y: 288
    width: 151
    height: 141
    visible: true


Text 
    id: text4
    x: 445
    y: 259
    text: qsTr("Main Battery")
    anchors.top: parent.top
    anchors.topMargin: -17
    fontSizeMode: Text.FixedSize
    horizontalAlignment: Text.AlignHCenter
    anchors.horizontalCenter: parent.horizontalCenter
    font.pixelSize: 12
    color: "grey"

Text 
    id: text6
    x: 64
    y: 106
    text: qsTr("Volts")
    anchors.bottom: parent.bottom
    anchors.bottomMargin: 10
    font.pixelSize: 12
    color: "grey"



Gauge 
    id: amphourgauge
    x: 803
    y: 103
    width: 114
    height: 294
    anchors.verticalCenterOffset: 0
    anchors.verticalCenter: parent.verticalCenter
    value: 50

    Text 
        id: text7
        x: 30
        y: 260
        text: qsTr("AMP HOURS")
        anchors.bottom: parent.bottom
        anchors.bottomMargin: -25
        anchors.horizontalCenter: parent.horizontalCenter
        font.pixelSize: 18
        color: "grey"
    





Button 
    id: amphourreset
    objectName: amphourreset
    x: 795
    y: 434
    text: qsTr("Reset")

    onClicked: dashboard.reset(amphourgauge.value)




Gauge 
    id: arraycurrent
    x: 621
    y: 160

    Text 
        id: text10
        text: qsTr("Array Current")
        font.pixelSize: 12
        color: "grey"
        anchors.top: parent.top
        anchors.topMargin: -17
        fontSizeMode: Text.FixedSize
        horizontalAlignment: Text.AlignHCenter
        anchors.horizontalCenter: parent.horizontalCenter
    


Gauge 
    id: motorcurrent
    x: 710
    y: 160

    Text 
        id: text9
        text: qsTr("Motor Current")
        font.pixelSize: 12
        color: "grey"
        anchors.top: parent.top
        anchors.topMargin: -17
        fontSizeMode: Text.FixedSize
        horizontalAlignment: Text.AlignHCenter
        anchors.horizontalCenter: parent.horizontalCenter
    


Connections 
    target: dashboard

    onAmpHourvalue: 
    // sub was set through arguments=['amphour']
        amphourgauge.value = amphour
        

    onAuxVoltage: 
    // sub was set through arguments=['auxvolt']
        auxvoltgauge.value = auxvolt
        

【问题讨论】:

您认为将其标记为“Java”会有所帮助吗? 嗯,我看到了 python、多线程 qml 和 PyQT5。 @JarrettDunn 我尝试运行你的代码但失败了。但是尝试这样的事情,threadclass.auxVoltage.connect(lambda aux: print(aux))main() 中。告诉我它是否有效。 @JarrettDunn 我删除了标签 :) @daegontaven 创建线程后,我将其添加到 main() 代码中。它有效,但正在打印一个随机数。如果您注释掉 ser=serial.Serial('COM6') 当然没有输入,代码应该运行,这不是您不知道是否有任何变化。 b'7:44:11, 0.0000, 0, 225, 213, 2124.8047N, 15746.0610W, 0.0\r\n' Aux 0.0000 Main 0 174163984 b'7:44:12, 0.0000, 0, 178, 1672, 2124.804 N, 15746.0610W, 0.0\r\n' 辅助 0.0000 主 0 174178688 b'7:44:13, 0.0000, 0, 202, 187, 2124.8047N, 15746.0610W, 0.0\r\n' 辅助 0.06536 主 0 【参考方案1】:

@daegontaven 是正确的。问题是线程没有连接到包含 GUI 的线程。连接两个线程解决了这个问题。我重新排序了一些代码。

class ThreadClass(QThread):
    # Create the signal
    ampHourvalue = pyqtSignal(float, arguments=['amphour'])
    auxVoltage = pyqtSignal(float, arguments=['auxvolt'])
    mainVoltage = pyqtSignal(float, arguments=['mainvolt'])
    arrayCurrent = pyqtSignal(float, arguments=['arraycurrent'])
    motorCurrent = pyqtSignal(float, arguments=['motorcur'])


    def __init__(self, parent=None):
        super(ThreadClass, self).__init__(parent)
        #connects  the signals from the thread to the signals in the thread that is running the GUI

        self.auxVoltage.connect(dashboard.auxVoltage)
        self.mainVoltage.connect(dashboard.mainVoltage)
        self.motorCurrent.connect(dashboard.motorCurrent)
        self.arrayCurrent.connect(dashboard.arrayCurrent)
        self.ampHourvalue.connect(dashboard.ampHourvalue)

【讨论】:

以上是关于信号未从线程传递到 GUI的主要内容,如果未能解决你的问题,请参考以下文章

与不是主线程的 GUI 线程通信

唤醒线程信号

如何从 non_GUI 类和我们可以在主 GUI 类中检测到的非 GUI 线程发出信号

Python Qt GUI设计:多线程中信号与槽的使用(基础篇—9)

python线程间通信的问题,回答有加分!300

PyQt5 - 如何从工作线程发出信号以通过 GUI 线程调用事件