PyQt线程:GUI交互崩溃程序

时间:2017-06-07 19:12:42

标签: python multithreading qt pyqt pyqt5

我正在设计一个编辑DICOM的程序。具体来说,我遇到了与PyQt UI正确交互的问题。

我希望能够点击“暂停”和“停止”按钮来暂停或停止我的编辑功能。我的编辑功能需要花费大量时间来处理/循环。根据正在编辑的文件数量,可能需要30秒到一个多小时。因此,我决定使用Qt的本机线程功能将我的编辑功能放入自己的线程中。我能够让线程工作,即:从我的MainWindow类中,我可以单击一个初始化我的编辑类的按钮(类编辑(QThread)),但是与GUI的交互仍然会崩溃程序,我不知道为什么!下面我添加了我正在使用的一般代码结构/设置的示例。

class anonymizeThread(QThread):
    def __init__(self):
        QThread.__init__(self)


    def __del__(self):
        self.wait()

    #def sendAnon(self, progress_val):
     #   self.completed = 0
      #  return self.completed


    def run(self):
            # while self.completed < 100:
            #     self.completed += 0.00001
            #     self.emit(QtCore.SIGNAL('PROGRESS'), self.completed)
            # ANONYMIZE FUNCTION!
            i = 0
            #flag = self.stop_flag
            while i < 10000000: # and self.stop_flag is not 1:
                print(i)
                i+=1
            print('i didnt enter the loop')


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)

        # connect the buttons
        self.worker = anonymizeThread()
        self.anonbtn.clicked.connect(self.anonymize)
        self.open_directory.clicked.connect(self.open_dir)
        self.pause.clicked.connect(self.paused)
        self.stopbtn.clicked.connect(self.stopped)

        # block button signals to start
        self.pause.blockSignals(True)
        self.stopbtn.blockSignals(True)

        self.dir_name = None
        self.pause_flag = None
        self.stop_flag = None
        self.anon_flag = None

        # This is how we quit from the main menu "File" option
        extractAction = self.actionQuit_Ctrl_Q
        extractAction.setShortcut("Ctrl+Q")
        extractAction.setStatusTip('Leave The App')
        extractAction.triggered.connect(self.close_application)



    def updateProgressBar(self,val):
        self.progressBar.setValue(val)
    def close_application(self):
        choice = QMessageBox.question(self, 'Just had to check...', "Are you sure you want to exit?", QMessageBox.Yes | QMessageBox.No)
        if choice == QMessageBox.Yes:
            sys.exit()
        else:
            pass

    def anonymize(self):
        self.pause.blockSignals(False)
        self.stopbtn.blockSignals(False)
        self.worker.start()
        # check if directory chosen
        # self.progressBar.setMaximum(len(dcm)
        # start our anon thread!


    def paused(self):
        #only if running
        if self.pause_flag is 0:
            self.pause_flag = 1
            self.pause.setText('Start')
        elif self.pause_flag is 1:
            self.pause_flag = 0
            self.pause.setText('Pause')
        else:
            pass

    def stopped(self): # need a self.stop() for anonThread

        choice = QMessageBox.question(self,'Stop', "Are you sure you want to stop? You will not be able to pick up exactly where you left off.",
                              QMessageBox.Yes | QMessageBox.No)
        if choice == QMessageBox.Yes:
            self.stop_flag = 1
            #self.stopbtn.blockSignals(True)
            #self.paused.blockSignals(True)
        else:
            pass


    def open_dir(self):
        self.dir_name = str(QFileDialog.getExistingDirectory(self, "Select Directory"))
        if len(self.dir_name) is not 0:
            self.anon_flag = 0




def main():
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

2 个答案:

答案 0 :(得分:0)

感谢@eyllansec和@ekhumoro ..

在上面的代码中,self.stop_flag = ...的所有实例都应该是self.worker.stop_flag = ...,因为它正在更改要在worker类/线程中使用的变量。我的错误是假设两个类继承了相同的“自我”。

如果有其他错误或更好地解释我做错了什么,请发一个答案,我会接受它!

答案 1 :(得分:0)

建议不要直接访问标志,最好通过函数来​​透明地使用它,因为同一个类应该验证任务。

还可以给出一个小延迟,以便应用程序可以处理图形部分,另一个可能的改进是避免使用sys.exit,你可以调用关闭窗口的close方法。

在下面的代码中,我实现了stop和pause方法。

class anonymizeThread(QThread):
    def __init__(self):
        QThread.__init__(self)
        self.onRunning = True
        self.onStop = False


    def __del__(self):
        self.wait()

    def stop(self):
        self.onStop = True

    def pause(self):
        if self.isRunning():
            self.onRunning = not self.onRunning


    def run(self):
            i = 0
            #flag = self.stop_flag
            while i < 10000000:
                if self.onRunning: # and self.stop_flag is not 1:
                    print(i)
                    i+=1

                if self.onStop:
                    break
                QThread.msleep(10)
            print('i didnt enter the loop')


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)


        # connect the buttons
        self.worker = anonymizeThread()
        self.anonbtn.clicked.connect(self.anonymize)
        self.pause.clicked.connect(self.paused)
        self.stopbtn.clicked.connect(self.stopped)

        # block button signals to start
        self.pause.blockSignals(True)
        self.stopbtn.blockSignals(True)

    def close_application(self):
        choice = QMessageBox.question(self, 'Just had to check...', "Are you sure you want to exit?", QMessageBox.Yes | QMessageBox.No)
        if choice == QMessageBox.Yes:
            self.close()

    def anonymize(self):
        self.pause.blockSignals(False)
        self.stopbtn.blockSignals(False)
        self.worker.start()


    def paused(self):
        self.worker.pause()

    def stopped(self): # need a self.stop() for anonThread

        choice = QMessageBox.question(self,'Stop', "Are you sure you want to stop? You will not be able to pick up exactly where you left off.",
                              QMessageBox.Yes | QMessageBox.No)
        if choice == QMessageBox.Yes:
            self.worker.stop()