gpt4 book ai didi

python - PyQt4:GUI 在长时间运行的循环中卡住

转载 作者:太空宇宙 更新时间:2023-11-03 16:18:16 25 4
gpt4 key购买 nike

我一直在 stackoverflow 和其他 pyqt 教程中寻找有关如何克服 pyqt4 中的 GUI 卡住问题的解决方案。有类似的主题建议使用以下方法来纠正它:

  • 将长时间运行的循环移至辅助线程,绘制 GUI 发生在主线程中。
  • 在循环中调用 app.processEvents()。这使 Qt 有机会处理事件并重绘 GUI。

我已经尝试了上述方法,但我的 GUI 仍然卡住。我在下面给出了导致问题的代码结构。

# a lot of headers
from PyQt4 import QtCore, QtGui
import time
import serial
from time import sleep
from PyQt4.QtCore import QThread, SIGNAL

getcontext().prec = 6
getcontext().rounding = ROUND_CEILING

adbPacNo = 0
sdbPacNo =0
tmPacNo = 0

try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s

try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)

#ADB Widget

class Ui_ADB(object):

def setupUi(self, ADB):
ADB.setObjectName(_fromUtf8("ADB"))
ADB.resize(1080, 212)
self.gridLayout_2 = QtGui.QGridLayout(ADB)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.verticalLayout = QtGui.QVBoxLayout()
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.label_20 = QtGui.QLabel(ADB)
font = QtGui.QFont()
font.setBold(True)
font.setUnderline(True)
font.setWeight(75)
self.label_20.setFont(font)
self.label_20.setAlignment(QtCore.Qt.AlignCenter)
self.label_20.setObjectName(_fromUtf8("label_20"))
.
# Rate X
self.rateX = QtGui.QLineEdit(ADB)
self.rateX.setReadOnly(True)
self.rateX.setObjectName(_fromUtf8("rateX"))
self.gridLayout.addWidget(self.rateX, 1, 6, 1, 1)
# Rate Z
self.rateZ = QtGui.QLineEdit(ADB)
self.rateZ.setReadOnly(True)
self.rateZ.setObjectName(_fromUtf8("rateZ"))
self.gridLayout.addWidget(self.rateZ, 1, 10, 1, 1)

# Rate Y
self.rateY = QtGui.QLineEdit(ADB)
self.rateY.setReadOnly(True)
self.rateY.setObjectName(_fromUtf8("rateY"))
self.gridLayout.addWidget(self.rateY, 1, 8, 1, 1)
# qv2

# qv1

# rateValid

# qv3

# qs

# and a lot more....

def retranslateUi(self, ADB):
# this contains the label definintions

# SDB Widget
class Ui_SDB(object):
def setupUi(self, SDB):
# again lot of fields to be displayed

def retranslateUi(self, SDB):
# this contains the label definintions

def sdbReader(self, sdbData):
#--- CRC Checking -------------------------------------------------#
global sdbPacNo
sdbPacNo+=1
tmCRC = sdbData[0:4];
data = sdbData[4:];
tmCRCResult = TM_CRCChecker(data,tmCRC)
if (tmCRCResult == 1):
print 'SDB Packet verification : SUCCESS!'
else:
print 'SDB packet verification : FAILED!'
quit()

#--- Type ID and Length -------------------------------------------#

# code to check the ID and length of the packet

#--- Reading out SDB into its respective variables ----------------#
# the code that performs the calculations and updates the parameters for GUI



## make thread for displaying ADB and SDB separately

# ADB Thread
class adbThread(QThread):
def __init__(self,Ui_ADB, adbData):
QThread.__init__(self)
self.adbData = adbData
self.Ui_ADB = Ui_ADB

def adbReader(self,adbData):
global adbPacNo
adbPacNo+=1;
#--- CRC Checking -------------------------------------------------#
tmCRC = self.adbData[0:4];
data = self.adbData[4:];
tmCRCResult = TM_CRCChecker(data,tmCRC)
if (tmCRCResult == 1):
print 'ADB Packet verification : SUCCESS!'
else:
print 'ADB packet verification : FAILED!'

#--- Type ID and Length -------------------------------------------#
# code to check the ID and length

#--- Reading out ADB into respective variables --------------------#
qvUnit = decimal.Decimal(pow(2,-30))
qv1 = qvUnit*decimal.Decimal(int(ADBlock[0:8],16))
qv1 = qv1.to_eng_string()
print 'qv1 = '+ qv1
self.Ui_ADB.qv1.setText(qv1)

# similar to above code there are many such variables that have to
# be calculated and printed on the respective fields.

def __del__(self):
self.wait()

def run(self):
self.adbReader(self.adbData)
myMessage = "ITS F** DONE!"
self.emit(SIGNAL('done(QString)'), myMessage)
print "I am in ADB RUN"


# SDB Thread
class sdbThread(QThread):
#similar type as of adbThread

# Global Variable to set the number of packets
packets=0

class mainwindow(QtGui.QMainWindow):

def __init__(self):
super(self.__class__, self).__init__()
self.setupUi(self)

def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(1153, 125)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.formLayout = QtGui.QFormLayout(self.centralwidget)
self.formLayout.setObjectName(_fromUtf8("formLayout"))
self.label = QtGui.QLabel(self.centralwidget)
self.label.setObjectName(_fromUtf8("label"))
self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.label)
self.serialStatus = QtGui.QLineEdit(self.centralwidget)
self.serialStatus.setReadOnly(True)
self.serialStatus.setObjectName(_fromUtf8("serialStatus"))
self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.serialStatus)
self.label_2 = QtGui.QLabel(self.centralwidget)
self.label_2.setObjectName(_fromUtf8("label_2"))
self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.label_2)
self.lineEdit = QtGui.QLineEdit(self.centralwidget)
self.lineEdit.setReadOnly(True)
self.lineEdit.setObjectName(_fromUtf8("lineEdit"))
self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.lineEdit)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1153, 25))
self.menubar.setObjectName(_fromUtf8("menubar"))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)

################################################################

#Setting up ADB
self.Ui_ADB = Ui_ADB()
self.myADB = QtGui.QWidget()
self.Ui_ADB.setupUi(self.myADB)
self.myADB.show()

# Setting up SDB
self.Ui_SDB = Ui_SDB()
self.mySDB = QtGui.QWidget()
self.Ui_SDB.setupUi(self.mySDB)

# Setting up the serial communication
self.tmSerial = serial.Serial('/dev/ttyACM0',9600)

self.sdb_Thread = sdbThread(self.Ui_SDB, self.mySDB)

buff = ''
tempByte= ''

counter =1

while counter<10:
# this reads the header of the SP

# Simulating the RTT signal trigger
self.tmSerial.write('y')
print "serial opened to read header"
tmSerialData = self.tmSerial.read(8*8)
print "tmSerialData="+str(tmSerialData)
littleEndian = tmSerialData[0:8*8]

# Converts the bitstream of SP header after converting to bigEndian
bufferData = bitstream_to_hex(littleEndian)
print "bufferData="+str(bufferData)

# Reads the header info : First 8 bytes
headerINFO = readHeader(bufferData)

# checking the packets in the headerINFO
# ADB & SDB present
global tmPacNo
if (headerINFO['adbINFO'] == 1 and headerINFO['sdbINFO'] == 1):
print 'Both ADB and SDB info are present'
tmPacNo+=1;

# Need to call both ADB and SDB
# Statements for reading the ADB
bufferData = tmSerial.read(42*8) # ADB packet bitstream
self.adbPacket = bitstream_to_hex(bufferData)

# Calling ADB thread
self.adb_Thread = adbThread(self.Ui_ADB, self.adbPacket)
self.adb_Thread.start()
#self.connect(self.adb_Thread, SIGNAL("finished()"),self.done)
self.connect(self.adb_Thread, SIGNAL("done(QString)"), self.done)
QtGui.QApplication.processEvents()

# IGNORED FOR NOW...
## Statements for reading the SDB
#bufferData = self.tmSerial.read(46*8) # SDB packet bitstream
#self.sdbPacket = bitstream_to_hex(bufferData)

## Calling SDB thread

#self.sdb_Thread.run(self.sdbPacket)


elif (headerINFO['adbINFO'] == 1 and headerINFO['sdbINFO'] == 0):
print 'ADB INFO only present'
tmPacNo+=1;

# Statements for reading the ADB
bufferData = self.tmSerial.read(42*8) # ADB packet bitstream
self.adbPacket = bitstream_to_hex(bufferData)
# Calling ADB thread
self.adb_Thread = adbThread(self.Ui_ADB, self.adbPacket)
self.adb_Thread.start()
#self.connect(self.adb_Thread, SIGNAL("finished()"),self.done)
self.connect(self.adb_Thread, SIGNAL("done(QString)"), self.done)
QtGui.QApplication.processEvents()

# IGNORED FOR NOW...
#elif (headerINFO['adbINFO'] == 0 and headerINFO['sdbINFO'] == 1):
#print 'SDB INFO only present'
#tmPacNo+=1;
## Statements for reading the SDB
#bufferData = self.tmSerial.read(46*8) # SDB packet bitstream
#self.sdbPacket = bitstream_to_hex(bufferData)
## Calling SDB thread

#self.sdb_Thread.run(sdbPacket)

#while (self.adb_Thread.isFinished() or self.sdb_Thread.isFinished() is False):
#print "waiting to complete adb Thread"

counter+=1

################################################################

def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
self.label.setText(_translate("MainWindow", "Serial Communication Status", None))
self.label_2.setText(_translate("MainWindow", "No. of SP_Packets Received", None))

####################################################################
def done(self,someText):
print someText + "the value has been updated"
self.myADB.show()



# This program converts the little endian bitstream -> BigEndian -> hex
def bitstream_to_hex(bitStream):
#global littleEndian
# small code for conversion


if __name__== "__main__":
import sys

# setting up the GUI
app = QtGui.QApplication(sys.argv)
main = mainwindow()
main.show()
sys.exit(app.exec_())

在上面的代码中可以注意到线程已经被实现,但我不确定我做错了什么?我已将长时间运行的循环 adbreader() 放入线程中,但 GUI 中的值并未响应更新。我只能在 while 循环运行 10 次后才能查看输出。

此外,我尝试使用QtGui.QApplication.processEvents(),这以某种方式设法在 GUI 中打印值,但我对这种方法不满意。(不高兴是因为,有时在迭代 5 时跳过打印,并在接下来的迭代 7 中打印值)非常感谢有关如何为此目的使用线程的一些指导。

最佳答案

根据three_pinapples的建议,我尝试通过创建更多线程来卸载程序。此外,我还调用了在 while 循环中执行整个串行写入和读取的线程。这导致了无论循环如何都只能调用线程一次的问题。我不确定为什么,但我想这可能是因为在循环中一次又一次地调用同一个对象?不确定。

我找到了解决这个问题的方法,即使用信号/槽机制作为递归函数,使线程保持无限运行模式,而不管 while 循环如何。我已经发布了以下代码的修改结构:

# a lot of headers
from PyQt4 import QtCore, QtGui
import time
import serial
from time import sleep
from PyQt4.QtCore import QThread, SIGNAL

getcontext().prec = 6
getcontext().rounding = ROUND_CEILING

adbPacNo = 0
sdbPacNo =0
tmPacNo = 0

try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s

try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)

#ADB Widget

class Ui_ADB(object):

def setupUi(self, ADB):


# Rate X

# Rate Z


# Rate Y


# qv2

# qv1

# rateValid

# qv3

# qs

# and a lot more....

def retranslateUi(self, ADB):
# this contains the label definintions


## make thread for displaying ADB and SDB separately

# ADB Thread
class adbThread(QThread):
def __init__(self,Ui_ADB, adbData):


def adbReader(self,adbData):
global adbPacNo
adbPacNo+=1;
#--- CRC Checking -------------------------------------------------#


#--- Type ID and Length -------------------------------------------#
# code to check the ID and length

#--- Reading out ADB into respective variables --------------------#


# similar to above code there are many such variables that have to
# be calculated and printed on the respective fields.

def __del__(self):
self.wait()

def run(self):
self.adbReader(self.adbData)
myMessage = "ITS F** DONE!"
self.emit(SIGNAL('done(QString)'), myMessage)
print "I am in ADB RUN"


# SDB Thread
class sdbThread(QThread):
#similar type as of adbThread

# Global Variable to set the number of packets
packets=0

# WorkerThread : This runs individually in the loop & call the respective threads to print.
class workerThread(QThread):

readComplete = QtCore.pyqtSignal(object)

def __init__(self, tmSerial, Ui_ADB, myADB, Ui_SDB, mySDB):
QThread.__init__(self)
self.tmSerial = tmSerial
self.Ui_ADB = Ui_ADB
self.myADB = myADB
self.Ui_SDB = Ui_SDB
self.mySDB = mySDB

def __del__(self):
self.wait()

def run(self):
print "worker = "+str(self.temp)
buff = ''
tempByte= ''

# Simulating the RTT signal trigger

self.tmSerial.write('y')

# Reading SP Header
tmSerialData = self.tmSerial.read(8*8)

# Converts the bitstream of SP header after converting to bigEndian
bufferData = bitstream_to_hex(littleEndian)

# Reads the header info : First 8 bytes
headerINFO = readHeader(bufferData)

# checking the packets in the headerINFO

global tmPacNo
if (headerINFO['adbINFO'] == 1 and headerINFO['sdbINFO'] == 1):
print 'Both ADB and SDB info are present'
tmPacNo+=1;

# Need to call both ADB and SDB
# Statements for reading the ADB
bufferData = tmSerial.read(42*8) # ADB packet bitstream
self.adbPacket = bitstream_to_hex(bufferData)

# Calling ADB thread
self.adb_Thread = adbThread(self.Ui_ADB, self.myADB, self.adbPacket)
self.adb_Thread.start()
self.adb_Thread.adbReadComplete.connect(self.adbdone)

# IGNORED -- Statements for reading the SDB


# Calling SDB thread

#self.sdb_Thread.run(self.sdbPacket)


elif (headerINFO['adbINFO'] == 1 and headerINFO['sdbINFO'] == 0):
print 'ADB INFO only present'
tmPacNo+=1;

# Statements for reading the ADB
bufferData = self.tmSerial.read(42*8) # ADB packet bitstream
self.adbPacket = bitstream_to_hex(bufferData)
# Calling ADB thread
self.adb_Thread = adbReadThread(self.Ui_ADB, self.myADB , self.adbPacket)
self.adb_Thread.start()
self.adb_Thread.adbReadComplete.connect(self.adbDone)

# IGNORED FOR NOW
#elif (headerINFO['adbINFO'] == 0 and headerINFO['sdbINFO'] == 1):
#print 'SDB INFO only present'
#tmPacNo+=1;
## Statements for reading the SDB
#bufferData = self.tmSerial.read(46*8) # SDB packet bitstream
#self.sdbPacket = bitstream_to_hex(bufferData)
## Calling SDB thread

#self.sdb_Thread.run(sdbPacket)
mess = "Worker Reading complete"

self.readComplete.emit(mess)


def adbDone(self,text):
print text
#self.myADB.show()



# Global Variable to set the number of packets
packets=0

class mainwindow(QtGui.QMainWindow):

def __init__(self):
super(self.__class__, self).__init__()
self.setupUi(self)

def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(1153, 125)
# ..... codes for main window GUI

################################################################

#Setting up ADB
self.Ui_ADB = Ui_ADB()
self.myADB = QtGui.QWidget()
self.Ui_ADB.setupUi(self.myADB)
#self.myADB.show()

# IGONRED FOR NOW -- Setting up SDB
self.Ui_SDB = Ui_SDB()
self.mySDB = QtGui.QWidget()
self.Ui_SDB.setupUi(self.mySDB)

# Setting up the serial communication
self.tmSerial = serial.Serial('/dev/ttyACM0',9600)

# IGONRED FOR NOW -- setting up the SDB read thread
#self.sdb_Thread = sdbReadThread(self.Ui_SDB, self.SDBPacket)

# *** MODIFIED ***
# Setting up the Worker thread
self.tmWorker = workerThread(self.tmSerial, self.Ui_ADB, self.myADB, Ui_SDB, self.mySDB)

# Code to call the thread that checks the serial data and print accordingly

self.tmWorker.start()
self.tmWorker.readComplete.connect(self.done) # This will act as a recursive function


def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
self.label.setText(_translate("MainWindow", "Serial Communication Status", None))
self.label_2.setText(_translate("MainWindow", "No. of SP_Packets Received", None))

####################################################################
def done(self):
print "worker reading done"
self.myADB.show()
self.tmWorker.start() #Modified
#sleep(01)

# This program converts the little endian bitstream -> BigEndian -> hex
def bitstream_to_hex(bitStream):
# Code for conversion

if __name__== "__main__":
import sys

# setting up the GUI
app = QtGui.QApplication(sys.argv)
main = mainwindow()
main.show()
sys.exit(app.exec_())

该程序现在运行良好,并且 GUI 似乎响应良好。但我发现 GUI 中存在一个问题,因为我不确定是否是因为程序运行速度比刷新帧所需的时间快得多。我发现这是因为放置在 GUI 中的计数器在更新值时会跳过一到两次计数。但 GUI 是响应的,并且在程序执行期间没有强制关闭。

希望这对正在寻找类似问题的人有所帮助。欢迎对故障和良好的编程技术有更多见解。谢谢。

关于python - PyQt4:GUI 在长时间运行的循环中卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38722219/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com