问题
I know this is a NOOB question; forgive me. I built a Pinewood Derby race timer (small car track) for Cub Scouts using a combination of an Arduino to control timing and RasPi for GUI display of lane place (1st, 2nd, 3rd, etc.) and run time in seconds (e.g. "2.1234"). I have the basic shell GUI setup in QT Creator and have successfully connected the Arduino & RasPi via USB. I am also successfully pulling the Arduino serial data into RasPi (tested with separate small Python code).
Problem I am having is the dynamic update of the QLabels in the GUI once the Arduino fires the race result strings via USB. in other words, when a race starts the Arduino sends "B" for begin (need GUI to blank previous results); when race is finished, Arduino sends "F" and then sends place "1" along with time "2.1234" and I need Python to update/change respective QLabels for each lane place and lane time. I am sure there is an easy way to do this, but I am unable to find how via searching this awesome website and others.
Thanks much in advance and I apologize for what is probably FUBAR coding that follows! The sample below only shows one lane vs. the 4x lanes I will use once I figure out how to do this.
There two Python codes I am working with:
Python code to interface with QT Creator generated XML code:
import sys
import time
import serial
from PyQt4 import QtCore, QtGui, uic
global ser
ser=serial.Serial("/dev/ttyUSB1",115200)
ser.flushInput()
qtCreatorFile = "PinewoodDisplay.ui" # Enter file here.
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class MyApp(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
while True:
if ser.inWaiting()>0:
inputValue = (ser.readline().strip())
self.Lane1_Place.setText(inputValue)
XML generated from QT Creator (not sure if I am posting this right) -- filename is "PinewoodDisplay.ui":
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>619</width>
<height>1051</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(102, 102, 108)</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QGroupBox" name="Lane1_Group">
<property name="geometry">
<rect>
<x>50</x>
<y>20</y>
<width>481</width>
<height>741</height>
</rect>
</property>
<property name="cursor">
<cursorShape>CrossCursor</cursorShape>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">background-color : rgb(0, 75, 0)</string>
</property>
<property name="title">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0">
<widget class="QLabel" name="Lane1_Place">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>75</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>75</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>75</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>75</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>75</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>75</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Button">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>75</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="ButtonText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>75</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>75</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<family>Gentium Book Basic</family>
<pointsize>350</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 255, 255)</string>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="text">
<string>4</string>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="Lane1_Time">
<property name="font">
<font>
<pointsize>90</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 255, 255)</string>
</property>
<property name="text">
<string>4.5678</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblLane1">
<property name="font">
<font>
<pointsize>36</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 255, 255)</string>
</property>
<property name="text">
<string><html><head/><body><p><span style=" color:#e9e9e9;">Lane 1</span></p></body></html></string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>619</width>
<height>27</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<action name="actionTest">
<property name="text">
<string>test</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
回答1:
Blocking tasks such as the while True that you need to read the serial data are not GUI-friendly, so you should not run on the same thread, the appropriate option is to execute them on another thread, and send the necessary information to the main thread by signals.
import sys
import serial
from PyQt4 import QtCore, QtGui, uic
qtCreatorFile = "PinewoodDisplay.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class SerialThread(QtCore.QThread):
dataChanged = QtCore.pyqtSignal(str)
def __init__(self, *args, **kwargs):
QtCore.QThread.__init__(self, *args, **kwargs)
self.ser = serial.Serial("/dev/ttyUSB1",115200)
def run(self):
while True:
if self.ser.inWaiting()>0:
inputValue = self.ser.readline().strip()
self.dataChanged.emit(inputValue)
class MyApp(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setupUi(self)
thread = SerialThread(self)
thread.dataChanged.connect(self.Lane1_Place.setText, QtCore.Qt.QueuedConnection)
thread.start()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
The same task could be done with QRunnable
and QThreadPool
, also to send the data you could use QMetaObject::invokeMethod()
来源:https://stackoverflow.com/questions/48359729/how-do-i-refresh-update-qlabel-with-data-from-usb-serial-from-arduino