PyQt5 多线程崩溃,没有控制台错误

Posted

技术标签:

【中文标题】PyQt5 多线程崩溃,没有控制台错误【英文标题】:PyQt5 Multithreading Crashes with No Console Error 【发布时间】:2021-07-13 18:26:44 【问题描述】:

我有一个正在工作的项目。由于项目的性质,我无法分享所有代码。

下面是我尝试在按钮单击时实现线程的代码。

from PyQt5 import QtCore, QtWidgets, QtGui, QtSerialPort
from PyQt5 import uic
import sys, time

class BETA_THREADED(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.ui = uic.loadUi('rocket_3.ui', self)
        # self.resize(1920, 1080)

        self.thread=
        self.launchButton.clicked.connect(self.start_worker)
        self.abortButton.clicked.connect(self.stop_worker)

    def start_worker(self):
        print('1')
        self.thread[1] = ThreadClass(parent = None, index = 1)
        self.thread[1].start()
        self.thread[1].any_signal.connect(self.launchSequence)
        self.launchButton.setEnabled(False)

    def stop_worker(self):
        self.thread[1].stop()
        self.launchButton.setEnabled(True)

    def launchSequence(self):
        print('Test')

class ThreadClass(QtCore.QThread):
    
    any_signal = QtCore.pyqtSignal(int)
    def __init__(self, parent=None,index=0):
        super(ThreadClass, self).__init__(parent)
        self.index=index
        self.is_running = True
    def run(self):
        print('Starting thread...',self.index)
        cnt=0
        while (True):
            cnt+=1
            if cnt==99: cnt=0
            time.sleep(0.01)
            self.any_signal.emit(cnt) 
    def stop(self):
        self.is_running = False
        print('Stopping thread...',self.index)
        self.terminate()

app = QtWidgets.QApplication(sys.argv)
mainWindow = BETA_THREADED()
mainWindow.show()
sys.exit(app.exec_())

UI文件由PyQt Designer生成,按钮为普通按钮。

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Rocket</class>
 <widget class="QMainWindow" name="Rocket">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>1262</width>
    <height>323</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Rocket</string>
  </property>
  <property name="styleSheet">
   <string notr="true"/>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QTextBrowser" name="statusBar">
    <property name="geometry">
     <rect>
      <x>230</x>
      <y>220</y>
      <width>1011</width>
      <height>61</height>
     </rect>
    </property>
   </widget>
   <widget class="QLabel" name="label_6">
    <property name="geometry">
     <rect>
      <x>230</x>
      <y>190</y>
      <width>111</width>
      <height>17</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <family>Carlito</family>
      <pointsize>14</pointsize>
     </font>
    </property>
    <property name="text">
     <string>STATUS</string>
    </property>
   </widget>
   <widget class="QGroupBox" name="groupBox">
    <property name="enabled">
     <bool>true</bool>
    </property>
    <property name="geometry">
     <rect>
      <x>-10</x>
      <y>-10</y>
      <width>221</width>
      <height>291</height>
     </rect>
    </property>
    <property name="title">
     <string/>
    </property>
    <property name="flat">
     <bool>false</bool>
    </property>
    <property name="checkable">
     <bool>false</bool>
    </property>
    <widget class="QPushButton" name="launchButton">
     <property name="geometry">
      <rect>
       <x>30</x>
       <y>60</y>
       <width>161</width>
       <height>101</height>
      </rect>
     </property>
     <property name="font">
      <font>
       <family>Carlito</family>
       <pointsize>14</pointsize>
      </font>
     </property>
     <property name="styleSheet">
      <string notr="true">background-color: blue;</string>
     </property>
     <property name="text">
      <string>LAUNCH</string>
     </property>
    </widget>
    <widget class="QPushButton" name="abortButton">
     <property name="geometry">
      <rect>
       <x>30</x>
       <y>180</y>
       <width>161</width>
       <height>101</height>
      </rect>
     </property>
     <property name="font">
      <font>
       <family>Carlito</family>
       <pointsize>14</pointsize>
      </font>
     </property>
     <property name="styleSheet">
      <string notr="true">background-color: red;</string>
     </property>
     <property name="text">
      <string>ABORT</string>
     </property>
    </widget>
   </widget>
  </widget>
 </widget>
 <tabstops>
  <tabstop>launchButton</tabstop>
  <tabstop>statusBar</tabstop>
  <tabstop>abortButton</tabstop>
 </tabstops>
 <resources/>
 <connections>
  <connection>
   <sender>launchButton</sender>
   <signal>clicked()</signal>
   <receiver>launchButton</receiver>
   <slot>click()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>546</x>
     <y>720</y>
    </hint>
    <hint type="destinationlabel">
     <x>546</x>
     <y>720</y>
    </hint>
   </hints>
  </connection>
  <connection>
   <sender>abortButton</sender>
   <signal>clicked()</signal>
   <receiver>abortButton</receiver>
   <slot>click()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>630</x>
     <y>910</y>
    </hint>
    <hint type="destinationlabel">
     <x>630</x>
     <y>910</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>

当我运行文件时,我的窗口会按预期打开,然后在单击任何按钮时关闭。我终其一生都无法弄清楚为什么。

编辑:更正了拼写和其他错误,提供了 python 和 UI 的完整文件。该程序仍然在任何按钮单击时关闭,并且在 cmd 中没有错误。

【问题讨论】:

【参考方案1】:

您在 Qt Designer 中连接信号时错误地指定了插槽

import sys, time
from PyQt5 import QtCore, QtWidgets, QtGui, QtSerialPort
from PyQt5 import uic


class Ui_Rocket(object):
    def setupUi(self, Rocket):
        Rocket.setObjectName("Rocket")
        Rocket.resize(1262, 323)
        Rocket.setStyleSheet("")
        self.centralwidget = QtWidgets.QWidget(Rocket)
        self.centralwidget.setObjectName("centralwidget")
        
        self.statusBar = QtWidgets.QTextBrowser(self.centralwidget)
        self.statusBar.setGeometry(QtCore.QRect(230, 220, 1011, 61))
        self.statusBar.setObjectName("statusBar")
        
        self.label_6 = QtWidgets.QLabel(self.centralwidget)
        self.label_6.setGeometry(QtCore.QRect(230, 190, 111, 17))
        font = QtGui.QFont()
        font.setFamily("Carlito")
        font.setPointSize(14)
        self.label_6.setFont(font)
        self.label_6.setObjectName("label_6")
        
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setEnabled(True)
        self.groupBox.setGeometry(QtCore.QRect(-10, -10, 221, 291))
        self.groupBox.setTitle("")
        self.groupBox.setFlat(False)
        self.groupBox.setCheckable(False)
        self.groupBox.setObjectName("groupBox")
        
        self.launchButton = QtWidgets.QPushButton(self.groupBox)
        self.launchButton.setGeometry(QtCore.QRect(30, 60, 161, 101))
        font = QtGui.QFont()
        font.setFamily("Carlito")
        font.setPointSize(14)
        self.launchButton.setFont(font)
        self.launchButton.setStyleSheet("background-color: blue;")
        self.launchButton.setObjectName("launchButton")
        
        self.abortButton = QtWidgets.QPushButton(self.groupBox)
        self.abortButton.setGeometry(QtCore.QRect(30, 180, 161, 101))
        font = QtGui.QFont()
        font.setFamily("Carlito")
        font.setPointSize(14)
        self.abortButton.setFont(font)
        self.abortButton.setStyleSheet("background-color: red;")
        self.abortButton.setObjectName("abortButton")
        
        Rocket.setCentralWidget(self.centralwidget)

        self.retranslateUi(Rocket)
#                                          ???????????????????????         
#        self.launchButton.clicked.connect(self.launchButton.click)
#        self.abortButton.clicked.connect(self.abortButton.click)
        
        QtCore.QMetaObject.connectSlotsByName(Rocket)
        Rocket.setTabOrder(self.launchButton, self.statusBar)
        Rocket.setTabOrder(self.statusBar, self.abortButton)

    def retranslateUi(self, Rocket):
        _translate = QtCore.QCoreApplication.translate
        Rocket.setWindowTitle(_translate("Rocket", "Rocket"))
        self.label_6.setText(_translate("Rocket", "STATUS"))
        self.launchButton.setText(_translate("Rocket", "LAUNCH"))
        self.abortButton.setText(_translate("Rocket", "ABORT"))


class ThreadClass(QtCore.QThread):
    any_signal = QtCore.pyqtSignal(int)

    def __init__(self, parent=None, index=0):
        super(ThreadClass, self).__init__(parent)
        self.index=index
        self.is_running = True
    def run(self):
        print('Starting thread...',self.index)
        cnt=0
        while (True):
            cnt+=1
            if cnt==99: cnt=0
            time.sleep(0.01)
            self.any_signal.emit(cnt) 
    def stop(self):
        self.is_running = False
        print('Stopping thread...',self.index)
        self.terminate()
        

class BETA_THREADED(QtWidgets.QMainWindow, Ui_Rocket):           # +++ , Ui_Rocket
    def __init__(self):
        super().__init__()
        
        self.setupUi(self)                                       # +++
        
#        self.ui = uic.loadUi('rocket_3.ui', self)
        # self.resize(1920, 1080)

        self.thread = 
        self.launchButton.clicked.connect(self.start_worker)
        self.abortButton.clicked.connect(self.stop_worker)

    def start_worker(self):
        print('111')
        
        self.thread[1] = ThreadClass(parent = None, index = 1)
        self.thread[1].start()
        self.thread[1].any_signal.connect(self.launchSequence)
        self.launchButton.setEnabled(False)
        
    def stop_worker(self):
        print('222')
        self.thread[1].stop()
        self.launchButton.setEnabled(True)

    def launchSequence(self):
        print('Test')


app = QtWidgets.QApplication(sys.argv)
mainWindow = BETA_THREADED()
mainWindow.show()
sys.exit(app.exec_())

【讨论】:

以上是关于PyQt5 多线程崩溃,没有控制台错误的主要内容,如果未能解决你的问题,请参考以下文章

PyQt5自学记录——PyQt5多线程实现详解

PyQt5使用多线程防止卡死

Pyqt5 多线程错误:QObject::connect: 无法对“QTextCursor”类型的参数进行排队

Python3.5+PyQt5多线程+itchat实现微信防撤回桌面版代码

多线程并发会造成程序周期性崩溃吗?

PyQt5创建多线程