У меня есть приложение, в котором я запускаю какой-то процесс во втором потоке, и в какой-то момент, при определенных условиях, открывается другое диалоговое окно, которое останавливает процесс, пока вы не подтвердите что-либо. Это вызывает следующее сообщение об ошибке:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QApplication(0x1f9c82383d0), parent's thread is QThread(0x1f9c7ade2a0), current thread is QThread(0x1f9c8358800)
Интересно, что если вы также наведете курсор на MainWindow
во время выполнения процесса и до появления нового диалогового окна, оно также выдаст это сообщение об ошибке a пару раз:
QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
Очень странно. Потому что только происходит, если вы наводите курсор на MainWindow
.
Теперь в моем приложении я фактически загружаю интерфейс для нового диалогового окна, которое появляется с помощью PyQt5.uic.loadUi
, и это не вызвало никаких проблем. Однако, когда я создавал пример для этого поста, возникла другая проблема из-за того, что я настраивал макет нового диалога во время его инициализации:
QObject::setParent: Cannot set parent, new parent is in a different thread
, что приводит к сбою приложения:
Process finished with exit code -1073741819 (0xC0000005)
Я, очевидно, делаю что-то не так в отношении потоков, я бы догадался, но я не знаю что. Меня особенно сбивает с толку тот факт, что я не могу установить макет нового диалога во время его инициализации, хотя использование loadUi
вполне подойдет. Вот мой пример кода:
import sys
import time
import numpy as np
from PyQt5.QtCore import QObject, pyqtSignal, QThread
from PyQt5.QtWidgets import (
QDialog, QApplication, QPushButton, QGridLayout, QProgressBar, QLabel
)
class SpecialDialog(QDialog):
def __init__(self):
super().__init__()
btn = QPushButton('pass variable')
btn.clicked.connect(self.accept)
layout = QGridLayout()
layout.addWidget(btn)
# self.setLayout(layout)
self.variable = np.random.randint(0, 100)
class Handler(QObject):
progress = pyqtSignal(int)
finished = pyqtSignal(int)
def __init__(self):
super().__init__()
self._isRunning = True
self._success = False
def run(self):
result = None
i = 0
while i < 100 and self._isRunning:
if i == 50:
dialog = SpecialDialog()
dialog.exec_()
result = dialog.variable
time.sleep(0.01)
i += 1
self.progress.emit(i)
if i == 100:
self._success = True
self.finished.emit(result)
def stop(self):
self._isRunning = False
class MainWindow(QDialog):
def __init__(self):
super().__init__()
btn = QPushButton('test')
btn.clicked.connect(self.run_test)
self.pbar = QProgressBar()
self.resultLabel = QLabel('Result:')
layout = QGridLayout(self)
layout.addWidget(btn)
layout.addWidget(self.pbar)
layout.addWidget(self.resultLabel)
self.setLayout(layout)
self.handler = None
self.handler_thread = QThread()
self.result = None
def run_test(self):
self.handler = Handler()
self.handler.moveToThread(self.handler_thread)
self.handler.progress.connect(self.progress)
self.handler.finished.connect(self.finisher)
self.handler_thread.started.connect(self.handler.run)
self.handler_thread.start()
def progress(self, val):
self.pbar.setValue(val)
def finisher(self, result):
self.result = result
self.resultLabel.setText(f'Result: {result}')
self.pbar.setValue(0)
self.handler.stop()
self.handler.progress.disconnect(self.progress)
self.handler.finished.disconnect(self.finisher)
self.handler_thread.started.disconnect(self.handler.run)
self.handler_thread.terminate()
self.handler = None
if __name__ == '__main__':
app = QApplication(sys.argv)
GUI = MainWindow()
GUI.show()
sys.exit(app.exec_())
РЕДАКТИРОВАТЬ
Я забыл упомянуть, что я уже нашел этот пост , который может быть связан с моя проблема, однако, я не понимаю причины решения в верхнем ответе, и что более важно, я не говорю то, что я считаю C ++.