2014-08-15 2 views
0

У меня есть программа PyQt5 в Python 3.3, которая будет запускать новый поток при каждом нажатии кнопки. Этот поток будет использовать всплывающие диалоговые окна. Он работает при первом нажатии кнопки, однако второй раз (после первого завершения) приведет к сбою программы. Я могу вызвать диалоговое окно столько раз, сколько хочу из потока, но во второй раз, когда поток запускается, программа зависает. Этот код воспроизведет проблему.PyQt5 QDialog в последующих потоках

import sys 
from threading import Thread 
from PyQt5 import QtWidgets, QtCore 


class Ui_Dialog(object): 
    def setupUi(self, Dialog): 
     Dialog.setObjectName("Dialog") 
     self.pushButton = QtWidgets.QPushButton(Dialog) 
     self.pushButton.setGeometry(QtCore.QRect(100, 100, 100, 50)) 
     self.pushButton.setObjectName("pushButton") 

     self.retranslateUi(Dialog) 
     QtCore.QMetaObject.connectSlotsByName(Dialog) 

    def retranslateUi(self, Dialog): 
     _translate = QtCore.QCoreApplication.translate 
     Dialog.setWindowTitle(_translate("Dialog", "Test")) 
     self.pushButton.setText(_translate("Dialog", "OK")) 


class Ui_MainWindow(object): 
    def setupUi(self, mainWindow): 
     mainWindow.setObjectName("mainWindow") 
     self.pushButton = QtWidgets.QPushButton(mainWindow) 
     self.pushButton.setGeometry(QtCore.QRect(30, 20, 100, 60)) 
     self.pushButton.setObjectName("pushButton") 

     self.retranslateUi(mainWindow) 
     QtCore.QMetaObject.connectSlotsByName(mainWindow) 

    def retranslateUi(self, Dialog): 
     _translate = QtCore.QCoreApplication.translate 
     Dialog.setWindowTitle(_translate("mainWindow", "Test")) 
     self.pushButton.setText(_translate("mainWindow", "Push Me!")) 


class TestDialog(QtWidgets.QDialog): 
    def __init__(self, parent=None): 
     super(TestDialog, self).__init__(parent) 
     self.ui = Ui_Dialog() 
     self.ui.setupUi(self) 
     # This message simply needs to go away when the button is pushed 
     self.ui.pushButton.clicked.connect(self.close) 

    def show_message(self): 
     super(TestDialog, self).exec_() 


class Main(QtWidgets.QMainWindow): 
    def __init__(self): 
     super(Main, self).__init__() 
     self.ui = Ui_MainWindow() 
     self.ui.setupUi(self) 

     self.dialog = TestDialog() 

     self.ui.pushButton.clicked.connect(self.start_thread) 

    def start_thread(self): 
     t = Thread(target=self.show_dialog) 
     t.daemon = True 
     t.start() 

    def show_dialog(self): 
     # Do lots of background stuff here 
     self.dialog.show_message() 
     # The dialog can be shown multiple times within the same thread 
     self.dialog.show_message() 


if __name__ == '__main__': 
    app = QtWidgets.QApplication(sys.argv) 
    window = Main() 
    window.show() 
    sys.exit(app.exec_()) 

Удалить сообщение диалогового окна, и оно работает. Так почему я не могу вызвать диалоговое окно из второго потока? Я не пытаюсь запускать два потока одновременно, но один за другим.

+0

Почему так много нитей ??? – mguijarr

+0

Вкратце: вы не должны создавать qwidgets для non-main-threads: http://qt-project.org/doc/qt-5/thread-basics.html#gui-thread-and-worker-thread – sebastian

+0

@ mguijarr: Идея состоит в том, чтобы запустить некоторые тесты продукта в фоновом режиме. Я хочу, чтобы пользователь смог снова запустить тесты после завершения теста. – Brickmastr

ответ

1

Я понял, благодаря помощи себастьяна. Я создал сигнальный объект, связал его с функцией show_message. Я также добавил сигнал, чтобы сообщить поток, когда диалог был принят. Вот рабочий код.

import sys 
from threading import Thread 
from PyQt5 import QtWidgets, QtCore 


class Ui_Dialog(object): 
    def setupUi(self, Dialog): 
     Dialog.setObjectName("Dialog") 
     self.pushButton = QtWidgets.QPushButton(Dialog) 
     self.pushButton.setGeometry(QtCore.QRect(100, 100, 100, 50)) 
     self.pushButton.setObjectName("pushButton") 

     self.retranslateUi(Dialog) 
     QtCore.QMetaObject.connectSlotsByName(Dialog) 

    def retranslateUi(self, Dialog): 
     _translate = QtCore.QCoreApplication.translate 
     Dialog.setWindowTitle(_translate("Dialog", "Test")) 
     self.pushButton.setText(_translate("Dialog", "OK")) 


class Ui_MainWindow(object): 
    def setupUi(self, mainWindow): 
     mainWindow.setObjectName("mainWindow") 
     self.pushButton = QtWidgets.QPushButton(mainWindow) 
     self.pushButton.setGeometry(QtCore.QRect(30, 20, 100, 60)) 
     self.pushButton.setObjectName("pushButton") 

     self.retranslateUi(mainWindow) 
     QtCore.QMetaObject.connectSlotsByName(mainWindow) 

    def retranslateUi(self, Dialog): 
     _translate = QtCore.QCoreApplication.translate 
     Dialog.setWindowTitle(_translate("mainWindow", "Test")) 
     self.pushButton.setText(_translate("mainWindow", "Push Me!")) 


class TestDialog(QtWidgets.QDialog): 
    signal = QtCore.pyqtSignal() 

    def __init__(self, parent=None): 
     super(TestDialog, self).__init__(parent) 
     self.ui = Ui_Dialog() 
     self.ui.setupUi(self) 
     # This message simply needs to go away 
     self.ui.pushButton.clicked.connect(self.close) 

    def show_message(self): 
     # Use this to display the pop-up so the text can be altered 
     super(TestDialog, self).exec_() 
     self.signal.emit() 


class Main(QtWidgets.QMainWindow): 
    signal = QtCore.pyqtSignal() 

    def __init__(self): 
     super(Main, self).__init__() 
     self.ui = Ui_MainWindow() 
     self.ui.setupUi(self) 

     self.dialog = TestDialog() 
     self.dialog_done = False 

     self.ui.pushButton.clicked.connect(self.start_thread) 

    def complete_dialog(self): 
     self.dialog_done = True 

    def wait_for_dialog(self): 
     while not self.dialog_done: 
      pass 
     self.dialog_done = False 

    def start_thread(self): 
     t = Thread(target=self.show_dialog) 
     t.daemon = True 
     t.start() 

    def show_dialog(self): 
     # Do lots of background stuff here 
     self.signal.emit() 
     # Wait for the dialog to get closed 
     self.wait_for_dialog() 


if __name__ == '__main__': 
    app = QtWidgets.QApplication(sys.argv) 
    window = Main() 
    window.show() 
    dialog = TestDialog() 
    window.signal.connect(dialog.show_message) 
    dialog.signal.connect(window.complete_dialog) 
    sys.exit(app.exec_()) 
Смежные вопросы