python - GUI 在工作人员的睡眠中冻结
问题描述
我创建了一个大型项目,涉及通过串行端口与控制器进行通信。我的项目分为3个文件:
文件 A - 一个 pyqt5 设计器文件 - 包括我所有的按钮、行编辑等。
文件 B - 串行通信文件 - 基本上是提出问题并从控制器接收答案。
文件 C - 主文件;在这个文件中,我正在导入文件 A 和文件 B 并使用它们。
在文件 C 中,我创建了一个工作线程,因此与控制器的所有通信都由该线程进行。(使用文件 B.. 的类和函数)
现在,我正在尝试在工作人员中创建一个新功能。这些函数time.sleep
每 x 秒使用 y 次。据我了解,因为我使用的是线程,所以 GUI 不应该卡住,但由于某种原因,它确实卡住了。
由于代码很长,我只附上了我认为与问题相关的内容。我试图复制尽可能少的代码,但仍然可以理解,我希望没问题。
文件 A - pyqt5 设计器代码:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
################creating general veriables#####################
MainWindow.setObjectName("MainWindow")
MainWindow.setFixedSize(780, 585)
font = QtGui.QFont()
font.setBold(False)
font.setWeight(50)
MainWindow.setFont(font)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.frame_Holder = QtWidgets.QFrame(self.centralwidget)
self.frame_Holder.setGeometry(QtCore.QRect(0, 85, 780, 500))
self.frame_Holder.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_Holder.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_Holder.setObjectName("frame_Holder")
#########################################################################
################creating veriables for the Top Frame#####################
self.frame_Top = QtWidgets.QFrame(self.centralwidget)
self.frame_Top.setEnabled(True)
self.frame_Top.setGeometry(QtCore.QRect(10, 5, 760, 80))
font = QtGui.QFont()
font.setStrikeOut(False)
self.frame_Top.setFont(font)
self.frame_Top.setFrameShape(QtWidgets.QFrame.WinPanel)
self.frame_Top.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_Top.setLineWidth(1)
self.frame_Top.setObjectName("frame_Top")
################creating Buttons#####################
self.btn_Connect = QtWidgets.QPushButton(self.frame_Top)
self.btn_Connect.setGeometry(QtCore.QRect(85, 50, 75, 23))
self.btn_Connect.setObjectName("btn_Connect")
self.btn_Connect.setEnabled(False)
self.btn_PortList = QtWidgets.QPushButton(self.frame_Top)
self.btn_PortList.setGeometry(QtCore.QRect(10, 50, 65, 23))
self.btn_PortList.setObjectName("btn_PortList")
self.productMenu=QtWidgets.QMenu(self.frame_Top)
self.btn_PortList.setMenu(self.productMenu)
self.btn_Init = QtWidgets.QPushButton(self.frame_Top)
self.btn_Init.setEnabled(False)
self.btn_Init.setGeometry(QtCore.QRect(300, 50, 75, 23))
self.btn_Init.setObjectName("btn_Init")
################creating text edits#####################
self.edit_version = QtWidgets.QLineEdit(self.frame_Top)
self.edit_version.setGeometry(QtCore.QRect(170, 50, 120, 23))
self.edit_version.setObjectName("edit_version")
self.edit_version.setEnabled(False)
################creating labels#####################
self.lbl_Version = QtWidgets.QLabel(self.frame_Top)
self.lbl_Version.setGeometry(QtCore.QRect(170, 30, 71, 21))
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(True)
font.setWeight(75)
self.lbl_Version.setFont(font)
self.lbl_Version.setObjectName("lbl_Version")
self.lbl_FrameTop = QtWidgets.QLabel(self.frame_Top)
self.lbl_FrameTop.setEnabled(True)
self.lbl_FrameTop.setGeometry(QtCore.QRect(5, 5, 90, 25))
font = QtGui.QFont()
font.setPointSize(12)
font.setBold(True)
font.setItalic(True)
font.setWeight(75)
font.setStrikeOut(False)
font.setKerning(True)
self.lbl_FrameTop.setFont(font)
self.lbl_FrameTop.setObjectName("lbl_FrameTop")
self.lbl_On = QtWidgets.QLabel(self.frame_Top)
self.lbl_On.setGeometry(QtCore.QRect(528, 30, 41, 16))
self.lbl_On.setObjectName("lbl_On")
self.lbl_Enable = QtWidgets.QLabel(self.frame_Top)
self.lbl_Enable.setGeometry(QtCore.QRect(560, 30, 41, 16))
self.lbl_Enable.setObjectName("lbl_Enable")
self.lbl_Rls = QtWidgets.QLabel(self.frame_Top)
self.lbl_Rls.setGeometry(QtCore.QRect(608, 30, 41, 16))
self.lbl_Rls.setObjectName("lbl_Rls")
self.lbl_Chk = QtWidgets.QLabel(self.frame_Top)
self.lbl_Chk.setGeometry(QtCore.QRect(645, 30, 41, 16))
self.lbl_Chk.setObjectName("lbl_Chk")
self.lbl_Wafer = QtWidgets.QLabel(self.frame_Top)
self.lbl_Wafer.setGeometry(QtCore.QRect(683, 30, 41, 16))
self.lbl_Wafer.setObjectName("lbl_Wafer")
self.lbl_Err = QtWidgets.QLabel(self.frame_Top)
self.lbl_Err.setGeometry(QtCore.QRect(725, 30, 20, 16))
self.lbl_Err.setObjectName("lbl_Err")
self.lbl_Port = QtWidgets.QLabel(self.frame_Top)
self.lbl_Port.setGeometry(QtCore.QRect(10, 30, 51, 21))
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(True)
font.setItalic(True)
font.setWeight(75)
self.lbl_Port.setFont(font)
self.lbl_Port.setObjectName("lbl_Port")
#########################################################################
self.frame_AutoRun = QtWidgets.QFrame(self.frame_Holder)
self.frame_AutoRun.setEnabled(False)
self.frame_AutoRun.setGeometry(QtCore.QRect(10, 90, 760, 320))
font = QtGui.QFont()
self.frame_AutoRun.setFont(font)
self.frame_AutoRun.setFrameShape(QtWidgets.QFrame.WinPanel)
self.frame_AutoRun.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_AutoRun.setLineWidth(1)
self.frame_AutoRun.setObjectName("frame_AutoRun")
self.lbl_AutoRun = QtWidgets.QLabel(self.frame_AutoRun)
self.lbl_AutoRun.setGeometry(QtCore.QRect(5, 5, 110, 25))
font = QtGui.QFont()
font.setPointSize(12)
font.setBold(True)
font.setItalic(True)
font.setWeight(75)
font.setStrikeOut(False)
font.setKerning(True)
self.lbl_AutoRun.setFont(font)
self.lbl_AutoRun.setObjectName("lbl_AutoRun")
self.btn_RunStop = QtWidgets.QPushButton(self.frame_AutoRun)
self.btn_RunStop.setGeometry(QtCore.QRect(500, 40, 60, 23))
font = QtGui.QFont()
font.setPointSize(8)
font.setBold(False)
font.setWeight(50)
font.setKerning(True)
self.btn_RunStop.setFont(font)
self.btn_RunStop.setObjectName("btn_RunStop")
########################4##########################
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "ECC GUI"))
self.btn_Connect.setText(_translate("MainWindow", "Connect"))
self.btn_PortList.setText(_translate("MainWindow", "Ports"))
self.lbl_Version.setText(_translate("MainWindow", "Version"))
self.btn_Init.setText(_translate("MainWindow", "Initiate"))
self.lbl_FrameTop.setText(_translate("MainWindow", "Connect"))##########
self.lbl_Port.setText(_translate("MainWindow", "Ports"))
self.lbl_On.setText(_translate("MainWindow", "ON"))
self.lbl_Enable.setText(_translate("MainWindow", "Enable"))
self.lbl_Rls.setText(_translate("MainWindow", "RLS"))
self.lbl_Chk.setText(_translate("MainWindow", "CHK"))
self.lbl_Wafer.setText(_translate("MainWindow", "Wafer"))
self.lbl_Err.setText(_translate("MainWindow", "ERR"))
self.lbl_AutoRun.setText(_translate("MainWindow", "Auto Run"))
self.btn_RunStop.setText(_translate("MainWindow", "Run"))
文件 B - 串行通信文件
import serial
from string import hexdigits
from re import search
class ECC():
def __init__(self,Port ):
self.ser = serial.Serial(port ='COM'+str(Port), baudrate= 38400,timeout=1)
def cmd(self,command):
return ('00'+command+chr(13)).encode('utf-8')
def disconnect(self):
self.ser.close()
def init(self):
self.ser.write(self.cmd('INI'))
return(self.ser.readline().decode('utf-8')[:3])
def spr(self,address,value):
self.ser.write(self.cmd('SPR'+str(address)+str(value)))
return (self.ser.readline().decode('utf-8')[:3])
def rpr(self,address):
self.ser.write(self.cmd('RPR'+str(address)))
return(self.ser.readline().decode('utf-8')[3:7])
def chuck(self):
self.ser.write(self.cmd('CHK'))
return(self.ser.readline().decode('utf-8')[:3])
def rls(self):
self.ser.write(self.cmd('RLS'))
return(self.ser.readline().decode('utf-8')[:3])
def cap(self):
self.ser.write(self.cmd('cap'))
cap=self.ser.readline()[3:].decode('utf-8')
cap=cap.rstrip()
if (all(c in hexdigits for c in cap) and cap!=""):
return int(cap,16)
else:
return("Busy...")
def version(self):
self.ser.write(self.cmd('VER'))
return(self.ser.readline().decode('utf-8')[:9])
def gst(self):
self.ser.flushInput()
self.ser.flushOutput()
self.ser.write(self.cmd('GST'))
gst=self.ser.readline()
gst=gst.decode('utf-8')
is_STV=search('^STV',str(gst))
if (is_STV):
stat_hex=gst[3:]
stat_bin=(bin(int(stat_hex,16))[2:].zfill(16))
stat_bool=[bool(int(bit)) for bit in stat_bin]
else:
stat_hex="ERR"
stat_bool="ERR"
return stat_hex, stat_bool
def statLights(self):
[stat_hex, stat_bool]=self.gst()
if(not stat_hex=="ERR"):
lights=[not(stat_bool[3]),not(stat_bool[5]),not(stat_bool[10]),stat_bool[10],stat_bool[11],stat_bool[0]]
else:
lights="ERR"
return lights
def msrphys(self):
self.ser.flushInput()
self.ser.flushOutput()
self.ser.write(self.cmd('msr'))
A=list()
A.append(self.ser.readline())
A[0]=A[0][3:7]
exists=search('[0-9A-Fa-f]{4}',str(A[0]))
if(exists):
A[0]=int(A[0],16)*-0.08398628+2500
for ind in range(1,32):
A.append(self.ser.readline())
exists=search('[0-9A-Fa-f]{4}',str(A[ind]))
if (exists):
A[ind]=int(A[ind].decode('utf-8'),16)*-0.08398628+2500
else:
A[0]="ERR"
break
self.ser.readline()
A[12]=A[12]*5.75
A[13]=A[13]*5.75
A[14]=A[14]*0.1
else:
A[0]="ERR"
return A
文件 C - 操作文件
from test_des import Ui_MainWindow
from PyQt5 import QtWidgets, QtCore, QtGui
from test_serialCom import ECC
import serial.tools.list_ports
import sys
from re import findall
import time
from functools import partial
try:
import queue
except ImportError:
import Queue as queue
class eccWorker(QtCore.QRunnable):
def __init__(self,port,q):
super(eccWorker, self).__init__()
self.finished = QtCore.pyqtSignal()
self.port=port
self.Q=q
self.threadactive=True
def run(self):
if(self.threadactive==True):
try:
self.ecc=ECC(self.port)
except:
self.threadactive=False
self.Q.put("ERROR-Not connected")
self.Q.put("ERROR-Not connected")
else:
self.Q.put(self.ecc.version())
self.Q.put(self.ecc.rpr('04'))
def init(self):
if(self.threadactive):
self.ecc.init()
def disconnect(self):
self.ecc.disconnect()
self.threadactive=False
def readCap(self):
if(self.threadactive==True):
self.Q.put(self.ecc.cap())
def chk(self):
if(self.threadactive==True):
self.ecc.chuck()
def rls(self):
if(self.threadactive==True):
self.ecc.rls()
def rprWorker(self,par):
if(self.threadactive==True):
self.Q.put(self.ecc.rpr(par))
def sprWorker(self,par,val):
if(self.threadactive==True):
# par=par.zfill(2)
isOk=self.ecc.spr(par,val)
if (isOk!="NAK"):
self.Q.put(self.ecc.rpr(par))
def getStat(self):
if(self.threadactive==True):
statLight=self.ecc.statLights()
if(statLight=="ERR"):
self.Q.put("ERR")
else:
for i in statLight:
self.Q.put(i)
def sprWorkerNoRpr(self,par,val):
if(self.threadactive==True):
isOk=self.ecc.spr(par,val)
if (isOk!="NAK"):
return True
def test1(self,Vchk,N,dt,Dt,threshold):
Vchk=str(Vchk).zfill(4)
if(self.sprWorkerNoRpr('04',Vchk)):
cap1=list()
cap2=list()
for i in range(N):
self.rls()
time.sleep(dt)
self.readCap()
res=self.Q.get()
if (res!="Busy..."):
cap1.append(int(str(res)))
time.sleep(Dt)
self.chk()
time.sleep(dt)
self.readCap()
res2=self.Q.get()
if (res2!="Busy..."):
cap2.append(int(str(res2)))
time.sleep(Dt)
self.rls()
cap_Rls=sum(cap1)/len(cap1)
cap_Chk=sum(cap2)/len(cap2)
if((max(cap2)-min(cap1))>threshold):
isPass=True
else:
isPass=False
self.Q.put(cap_Rls)
self.Q.put(cap_Chk)
self.Q.put(isPass)
print("Done!")
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super(ApplicationWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.threadpool=QtCore.QThreadPool()
self.Q=queue.Queue()
self.ui.productMenu.aboutToShow.connect(self.findPort)
self.ui.btn_Connect.clicked.connect(self.connectClicked)
self.ui.btn_RunStop.clicked.connect(self.run)
self.ui.btn_Init.clicked.connect(self.initClicked)
self.redOff=QtGui.QColor(120,0,0)
self.redOn=QtGui.QColor(255,0,0)
self.grnOff=QtGui.QColor(7,100,0)
self.grnOn=QtGui.QColor(16,243,0)
self.yelOff=QtGui.QColor(155,80,0)
self.yelOn=QtGui.QColor(255,127,0)
self.onPen=QtGui.QPen(self.grnOff, 8, QtCore.Qt.SolidLine)
self.enablePen=QtGui.QPen(self.grnOff, 8, QtCore.Qt.SolidLine)
self.rlsPen=QtGui.QPen(self.grnOff, 8, QtCore.Qt.SolidLine)
self.chkPen=QtGui.QPen(self.grnOff, 8, QtCore.Qt.SolidLine)
self.waferPen=QtGui.QPen(self.yelOff, 8, QtCore.Qt.SolidLine)
self.errPen=QtGui.QPen(self.redOff, 8, QtCore.Qt.SolidLine)
def paintEvent(self, e):
onLedPainter = QtGui.QPainter(self)
onLedPainter.setPen(self.onPen)
onLedPainter.setBrush(self.grnOff)
onLedPainter.drawEllipse(540,55,10,10)
enabledLedPainter = QtGui.QPainter(self)
enabledLedPainter.setPen(self.enablePen)
enabledLedPainter.setBrush(self.grnOff)
enabledLedPainter.drawEllipse(580,55,10,10)
rlsLedPainter = QtGui.QPainter(self)
rlsLedPainter.setPen(self.rlsPen)
rlsLedPainter.setBrush(self.grnOff)
rlsLedPainter.drawEllipse(620,55,10,10)
chkLedPainter = QtGui.QPainter(self)
chkLedPainter.setPen(self.chkPen)
chkLedPainter.setBrush(self.grnOff)
chkLedPainter.drawEllipse(660,55,10,10)
waferLedPainter = QtGui.QPainter(self)
waferLedPainter.setPen(self.waferPen)
waferLedPainter.setBrush(self.yelOff)
waferLedPainter.drawEllipse(700,55,10,10)
errLedPainter = QtGui.QPainter(self)
errLedPainter.setPen(self.errPen)
errLedPainter.setBrush(self.redOff)
errLedPainter.drawEllipse(740,55,10,10)
def updateStat(self):
#####updating LEDs####
self.worker.getStat()
self.ledStat=list()
self.ledStat.append(self.worker.Q.get())
if(not self.ledStat[0]=="ERR"):
for i in range(5):
self.ledStat.append(self.worker.Q.get())
if(self.ledStat[0]):
self.onPen=QtGui.QPen(self.grnOn, 8, QtCore.Qt.SolidLine)
else:
self.onPen=QtGui.QPen(self.grnOff, 8, QtCore.Qt.SolidLine)
if(self.ledStat[1]):
self.enablePen=QtGui.QPen(self.grnOn, 8, QtCore.Qt.SolidLine)
else:
self.enablePen=QtGui.QPen(self.grnOff, 8, QtCore.Qt.SolidLine)
if(self.ledStat[2]):
self.rlsPen=QtGui.QPen(self.grnOn, 8, QtCore.Qt.SolidLine)
self.chkPen=QtGui.QPen(self.grnOff, 8, QtCore.Qt.SolidLine)
else:
self.chkPen=QtGui.QPen(self.grnOn, 8, QtCore.Qt.SolidLine)
self.rlsPen=QtGui.QPen(self.grnOff, 8, QtCore.Qt.SolidLine)
if(self.ledStat[4]):
self.waferPen=QtGui.QPen(self.yelOn, 8, QtCore.Qt.SolidLine)
else:
self.waferPen=QtGui.QPen(self.yelOff, 8, QtCore.Qt.SolidLine)
if(self.ledStat[5]):
self.errPen=QtGui.QPen(self.redOn, 8, QtCore.Qt.SolidLine)
else:
self.errPen=QtGui.QPen(self.redOff, 8, QtCore.Qt.SolidLine)
self.update()
else:
self.connectClicked()
self.ui.edit_version.setText("GST Disconnected!")
def findPort(self):
self.ui.productMenu.clear()
comPorts = list(serial.tools.list_ports.comports()) # get a list of all devices connected through serial port
comPorts=sorted(comPorts)
for port in comPorts:
self.ui.productMenu.addAction(str(port),self.selectedPort)
def selectedPort(self):
self.portNum=self.sender()
self.portNum=self.portNum.text()
self.portNum=findall("COM\d+",self.portNum)
self.ui.btn_PortList.setText(str(self.portNum[0]))
self.portNum=self.portNum[0][3:]
self.ui.btn_Connect.setEnabled(True)
def connectClicked(self):
if (self.ui.btn_Connect.text()=="Connect"):
self.worker=eccWorker(self.portNum,self.Q)
self.threadpool.start(self.worker)
ver=self.worker.Q.get()
volHex=self.worker.Q.get()
if(ver[:3]=="VER"):
self.ui.btn_Connect.setText("Disconnect")
self.ui.btn_PortList.setEnabled(False)
self.ui.edit_version.setText(ver)
self.ui.btn_Init.setEnabled(True)
self.ui.frame_AutoRun.setEnabled(True)
self.timer_updateStat = QtCore.QTimer()
self.timer_updateStat.setInterval(500)
self.timer_updateStat.timeout.connect(self.updateStat)
self.timer_updateStat.start()
else:
self.ui.edit_version.setText("Error!")
else:
self.timer_updateStat.stop()
self.worker.disconnect()
self.ui.btn_Connect.setText("Connect")
self.ui.btn_Connect.setEnabled(False)
self.ui.btn_Init.setEnabled(False)
self.ui.frame_AutoRun.setEnabled(False)
self.ui.btn_PortList.setEnabled(True)
self.ui.edit_version.clear()
self.setFixedSize(780,585)
self.ui.btn_PortList.setText("Ports")
self.onPen=QtGui.QPen(self.grnOff, 8, QtCore.Qt.SolidLine)
self.enablePen=QtGui.QPen(self.grnOff, 8, QtCore.Qt.SolidLine)
self.chkPen=QtGui.QPen(self.grnOff, 8, QtCore.Qt.SolidLine)
self.rlsPen=QtGui.QPen(self.grnOff, 8, QtCore.Qt.SolidLine)
self.waferPen=QtGui.QPen(self.yelOff, 8, QtCore.Qt.SolidLine)
self.errPen=QtGui.QPen(self.redOff, 8, QtCore.Qt.SolidLine)
self.update()
def initClicked(self):
self.worker.init()
def run(self):
self.worker.test1(200,5,0.2,0.3,100)
cap_Rls=self.Q.get()
cap_Chk=self.Q.get()
ispass=self.Q.get()
print("cap_Rls:\n")
print(cap_Rls)
print("cap_Chk:\n")
print(cap_Chk)
print(ispass)
def closeEvent(self,event):
try:
self.worker.disconnect()
finally:
sys.exit()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
application = ApplicationWindow()
application.show()
sys.exit(app.exec_())
那么即使我使用的是线程,GUI 在函数执行期间会卡住什么?我能做些什么来解决这个问题?
另外,理想情况下,我想要另一个文件,文件 D,它包含一个名为 TESTS 的主类,其中有 5 个函数,每个函数代表一个测试。我在执行上述操作时遇到的问题是无法从文件 C 中的活动线程调用/获取信息,因此,如果您也知道如何制作这个,将不胜感激。(如果不创建另一个文件,那么将所有测试存储在不同的类中。在这里,我也遇到了一些问题并且无法使其工作)。
解决方案
经过许多小时的在线搜索后,我发现使用QtTest.QTest.qWait(msecs)
而不是sleep
给了我想要的结果 - 它包含命令但不会使 GUI 冻结。为了使用它,我必须使用from PyQt5 import QtTest
.
如果有人有更好的建议(对上述任何问题),我很乐意看到他们。
推荐阅读
- powershell - Powershell Like 运算符调用 REST 错误
- c# - Windows或浏览器是否保存X509证书的签名?
- inno-setup - Inno Setup:只运行一次卸载脚本
- ios - 为什么 CollectionViewCell 在上下滚动时出现故障?
- mosquitto - 本地 mosquitto 代理不会将发布的消息发送到远程 mosquitto 代理
- javascript - 如何检查使用时间选择器的两个字段的时间差
- css - 设置为“无”后重新设置滚动捕捉类型无效
- ios - 在 iOS 上检查人脸边缘角度
- docker - 在 docker-for-desktop OSX 上删除 kubernetes 集群?
- r - 反应性闪亮对象类型闭包不可子集