Проблема в том, что вы путаете, что QThread
- это Qt-поток , то есть новый поток, созданный Qt, но нет, QThread
- это класс, который обрабатывает нативные потоки, только метод run()
выполняется в другом потоке, другие методы живут в потоке, в котором находится QThread
, то есть QObject
,
В каком потокеa QObject live?
Поток, в котором живет QObject
, является потоком родителя, если у него нет родителя, он будет потоком, в котором он был создан.С другой стороны, QObject
может перейти в другой поток, используя moveToThread()
, и все его дочерние элементы также будут перемещены.Только moveToThread()
может использоваться, если QObject
не имеет родителя, в противном случае произойдет сбой.
Методология использования QThread
заключается в создании класса, который наследуется от QThread
, и переопределенииметод run и вызов start()
, чтобы запустить его run()
, в методе run()
тяжелая задача будет выполнена, но в вашем случае нет. Эту форму можно использовать, поскольку задача не будет выполняться непрерывно.Лучшим вариантом, чем тяжелая задача, является часть QObject
, и QObject
перемещает ее в другой поток.
class MainWindow(QMainWindow):
change_text = pyqtSignal(str)
def __init__(self):
super().__init__()
self.button = QPushButton('Push me!', self)
self.setCentralWidget(self.button)
print('main running in:', QThread.currentThread())
# A Worker without a parent is created
# so that it can be moved to another thread.
self.worker = Worker(self.change_text)
thread = QThread(self)
self.worker.moveToThread(thread)
thread.start()
# All methods of self.worker are now executed in another thread.
self.button.clicked.connect(self.worker.do_something_slow)
self.change_text.connect(self.display_changes)
@pyqtSlot(str)
def display_changes( self, text ):
self.button.setText(text)
class Worker(QObject):
def __init__(self, signal_to_emit, parent=None):
super().__init__(parent)
self.signal_to_emit = signal_to_emit
@pyqtSlot()
def do_something_slow( self ):
print('Slot doing stuff in:', QThread.currentThread())
import time
time.sleep(5)
self.signal_to_emit.emit('I did something')
С другой стороны, указывать тип соединения не обязательно, посколькупо умолчанию это Qt::AutoConnection
, этот тип соединения решает во время выполнения, если вы используете Qt::DirectConnection
, если приемник живет в том же проводе, откуда исходил сигнал, в противном случае используется Qt::QueuedConnection
.Как вы понимаете, у Worker нет родителя, поэтому для жизненного цикла, равного классу, он должен быть его атрибутом, поскольку в противном случае это будет локальная переменная, которая будет исключена.С другой стороны, обратите внимание, что QThread
получает родительский объект, а не MainWindow, поэтому QThread
будет жить в потоке GUI, но обрабатывает вторичный поток.
С концепцией Worker лучшечто сигнал change_text больше не принадлежит графическому интерфейсу, а рабочему лучше отсоединяет объекты.
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.button = QPushButton('Push me!', self)
self.setCentralWidget(self.button)
print('main running in:', QThread.currentThread())
self.worker = Worker()
thread = QThread(self)
self.worker.moveToThread(thread)
thread.start()
self.button.clicked.connect(self.worker.do_something_slow)
self.worker.change_text.connect(self.display_changes)
@pyqtSlot(str)
def display_changes( self, text ):
self.button.setText(text)
class Worker(QObject):
change_text = pyqtSignal(str)
@pyqtSlot()
def do_something_slow( self ):
print('Slot doing stuff in:', QThread.currentThread())
import time
time.sleep(5)
self.change_text.emit('I did something')