gpt4 book ai didi

python - PyQt5 QThread 不工作,gui 仍然卡住

转载 作者:行者123 更新时间:2023-11-30 22:14:12 25 4
gpt4 key购买 nike

我有这个代码(如果你有pyqt5,你应该能够自己运行它):

import sys
import time

from PyQt5.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
from PyQt5.QtCore import QObject, QThread, pyqtSignal, pyqtSlot


class Worker(QObject):
def __init__(self):
super().__init__()
self.thread = None


class Tab(QObject):
def __init__(self, _main):
super().__init__()
self._main = _main


class WorkerOne(Worker):
finished = pyqtSignal()

def __init__(self):
super().__init__()

@pyqtSlot(str)
def print_name(self, name):
for _ in range(100):
print("Hello there, {0}!".format(name))
time.sleep(1)

self.finished.emit()
self.thread.quit()


class SomeTabController(Tab):
def __init__(self, _main):
super().__init__(_main)
self.threads = {}

self._main.button_start_thread.clicked.connect(self.start_thread)

# Workers
self.worker1 = WorkerOne()
#self.worker2 = WorkerTwo()
#self.worker3 = WorkerThree()
#self.worker4 = WorkerFour()

def _threaded_call(self, worker, fn, *args, signals=None, slots=None):
thread = QThread()
thread.setObjectName('thread_' + worker.__class__.__name__)

# store because garbage collection
self.threads[worker] = thread

# give worker thread so it can be quit()
worker.thread = thread

# objects stay on threads after thread.quit()
# need to move back to main thread to recycle the same Worker.
# Error is thrown about Worker having thread (0x0) if you don't do this
worker.moveToThread(QThread.currentThread())

# move to newly created thread
worker.moveToThread(thread)

# Can now apply cross-thread signals/slots

#worker.signals.connect(self.slots)
if signals:
for signal, slot in signals.items():
try:
signal.disconnect()
except TypeError: # Signal has no slots to disconnect
pass
signal.connect(slot)

#self.signals.connect(worker.slots)
if slots:
for slot, signal in slots.items():
try:
signal.disconnect()
except TypeError: # Signal has no slots to disconnect
pass
signal.connect(slot)

thread.started.connect(lambda: fn(*args)) # fn needs to be slot
thread.start()

@pyqtSlot()
def _receive_signal(self):
print("Signal received.")

@pyqtSlot(bool)
def start_thread(self):
name = "Bob"
signals = {self.worker1.finished: self._receive_signal}
self._threaded_call(self.worker1, self.worker1.print_name, name,
signals=signals)


class MainWindow(QWidget):
def __init__(self):
super().__init__()

self.setWindowTitle("Thread Example")
form_layout = QVBoxLayout()
self.setLayout(form_layout)
self.resize(400, 400)

self.button_start_thread = QPushButton()
self.button_start_thread.setText("Start thread.")
form_layout.addWidget(self.button_start_thread)

self.controller = SomeTabController(self)


if __name__ == '__main__':
app = QApplication(sys.argv)

_main = MainWindow()
_main.show()

sys.exit(app.exec_())

但是,WorkerOne 仍然阻塞我的 GUI 线程,并且当 WorkerOne.print_name 运行时窗口没有响应。

我最近对 ​​QThreads 进行了很多研究,根据我所做的研究,我不确定为什么这不起作用。

什么给了?

最佳答案

问题是由与 lambda 方法的连接引起的,因为该 lambda 不是 Worker 的一部分,因此它不会在新线程上运行。解决方案是使用functools.partial :

from functools import partial
...
thread.started.connect(partial(fn, *args))

完整代码:

import sys
import time

from functools import partial

from PyQt5.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
from PyQt5.QtCore import QObject, QThread, pyqtSignal, pyqtSlot


class Worker(QObject):
def __init__(self):
super().__init__()
self.thread = None


class Tab(QObject):
def __init__(self, _main):
super().__init__()
self._main = _main


class WorkerOne(Worker):
finished = pyqtSignal()

def __init__(self):
super().__init__()

@pyqtSlot(str)
def print_name(self, name):
for _ in range(100):
print("Hello there, {0}!".format(name))
time.sleep(1)

self.finished.emit()
self.thread.quit()


class SomeTabController(Tab):
def __init__(self, _main):
super().__init__(_main)
self.threads = {}

self._main.button_start_thread.clicked.connect(self.start_thread)

# Workers
self.worker1 = WorkerOne()
#self.worker2 = WorkerTwo()
#self.worker3 = WorkerThree()
#self.worker4 = WorkerFour()

def _threaded_call(self, worker, fn, *args, signals=None, slots=None):
thread = QThread()
thread.setObjectName('thread_' + worker.__class__.__name__)

# store because garbage collection
self.threads[worker] = thread

# give worker thread so it can be quit()
worker.thread = thread

# objects stay on threads after thread.quit()
# need to move back to main thread to recycle the same Worker.
# Error is thrown about Worker having thread (0x0) if you don't do this
worker.moveToThread(QThread.currentThread())

# move to newly created thread
worker.moveToThread(thread)

# Can now apply cross-thread signals/slots

#worker.signals.connect(self.slots)
if signals:
for signal, slot in signals.items():
try:
signal.disconnect()
except TypeError: # Signal has no slots to disconnect
pass
signal.connect(slot)

#self.signals.connect(worker.slots)
if slots:
for slot, signal in slots.items():
try:
signal.disconnect()
except TypeError: # Signal has no slots to disconnect
pass
signal.connect(slot)

thread.started.connect(partial(fn, *args)) # fn needs to be slot
thread.start()

@pyqtSlot()
def _receive_signal(self):
print("Signal received.")

@pyqtSlot(bool)
def start_thread(self):
name = "Bob"
signals = {self.worker1.finished: self._receive_signal}
self._threaded_call(self.worker1, self.worker1.print_name, name,
signals=signals)


class MainWindow(QWidget):
def __init__(self):
super().__init__()

self.setWindowTitle("Thread Example")
form_layout = QVBoxLayout()
self.setLayout(form_layout)
self.resize(400, 400)

self.button_start_thread = QPushButton()
self.button_start_thread.setText("Start thread.")
form_layout.addWidget(self.button_start_thread)

self.controller = SomeTabController(self)


if __name__ == '__main__':
app = QApplication(sys.argv)

_main = MainWindow()
_main.show()

sys.exit(app.exec_())

关于python - PyQt5 QThread 不工作,gui 仍然卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50596027/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com