PyQt5 black window while threads are working
PyQt5 black window while threads are working
我正在 PyQt5 中制作 window 应用程序,我想在后台解析来自 XML 文件的数据并将其发送到第二个 class。我想使用带队列的线程来处理它们。当我想显示 window 应用程序时,我看到黑色 window。使用 python 线程会很好,但我尝试在 QThread 上执行此操作,但它也无法正常工作,我知道为什么...
这是代码示例
import queue
import sys
import threading
from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import *
class Test_generator:
def __init__(self, queue_obj):
super().__init__()
self.queue_obj = queue_obj
#self.parser_thread = threading.Thread(target=self.parser())
def sender(self):
for _ in range(100):
string ="test"
self.queue_obj.put(string)# send to queue
time.sleep(1)
#print(string)
class Test_collectioner:
def __init__(self,queue_obj):
self.queue_obj = queue_obj
def get_data(self):
collection = []
while self.queue_obj.empty() is False:
print("xd")
print(self.queue_obj.get(), "xd")
#I found this example in the internet(Not working)
class Threaded(QThread):
result = pyqtSignal(int)
def __init__(self, parent=None, **kwargs):
super().__init__(parent, **kwargs)
@pyqtSlot(int)
def run(self):
while True:
print("test")
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.GUI()
self.setWindowTitle("PyQt5 app")
global q
q = queue.Queue()
# BLACKSCREEN (for Test_generator)
test_generator_obj = Test_generator(q)
test_collectioner_obj = Test_collectioner(q)
t1 = threading.Thread(target=test_generator_obj.sender())
t2 = threading.Thread(target=test_collectioner_obj.get_data())
t1.start()
t2.start()
# BLACKSCREEN TOO
"""self.thread = QThread()
self.threaded = Threaded()
self.thread.started.connect(self.threaded.run())
self.threaded.moveToThread(self.thread)
qApp.aboutToQuit.connect(self.thread.quit)
self.thread.start()"""
def GUI(self):
self.showMaximized()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
您的代码中存在两个主要问题:
您正在执行线程使用的方法,但您应该使用可调用对象;你对 QThread 犯了同样的错误,因为信号的连接也需要一个可调用的,但你实际上是 执行 来自主线程的 run
函数(完全阻止一切) ,因为您使用的是括号;这些行应该是这样的:
t1 = threading.Thread(target=test_generator_obj.sender)
t2 = threading.Thread(target=test_collectioner_obj.get_data)
或者,对于 QThread:
self.thread.started.connect(self.threaded.run)
由于 python GIL,多线程只会在允许的情况下将控制权释放给其他线程,但是您使用的 while
循环会阻止这种情况;添加一个小的睡眠函数确保控制周期性地返回到主线程;
还存在其他问题:
- 您已经在使用 QThread 的子类,因此使用 另一个 QThread 并将您的子类移至它是没有用的;
- 即使假设一个对象被移动到另一个线程,槽也不应该用参数修饰,因为 QThread 的
started
信号没有任何;还考虑到很少需要插槽装饰器;
- 线程
quit()
只停止了线程的事件循环,但是如果run
被重写了,实际上并没有启动事件循环;如果你想停止一个带有 run
实现的线程,应该使用 运行 标志来代替;在任何其他情况下,退出应用程序通常足以停止一切;
请注意,如果您想与 UI 交互,您只能使用 QThread 和自定义信号,而基本的 python 线程不提供合适的机制。
class Threaded(QThread):
result = pyqtSignal(int)
def __init__(self, parent=None, **kwargs):
super().__init__(parent, **kwargs)
def run(self):
self.keepGoing = True
while self.keepGoing:
print("test")
self.msleep(1)
def stop(self):
self.keepGoing = False
class MainWindow(QMainWindow):
def __init__(self):
# ...
self.threaded = Threaded()
self.threaded.start()
qApp.aboutToQuit.connect(self.threaded.stop)
我正在 PyQt5 中制作 window 应用程序,我想在后台解析来自 XML 文件的数据并将其发送到第二个 class。我想使用带队列的线程来处理它们。当我想显示 window 应用程序时,我看到黑色 window。使用 python 线程会很好,但我尝试在 QThread 上执行此操作,但它也无法正常工作,我知道为什么... 这是代码示例
import queue
import sys
import threading
from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import *
class Test_generator:
def __init__(self, queue_obj):
super().__init__()
self.queue_obj = queue_obj
#self.parser_thread = threading.Thread(target=self.parser())
def sender(self):
for _ in range(100):
string ="test"
self.queue_obj.put(string)# send to queue
time.sleep(1)
#print(string)
class Test_collectioner:
def __init__(self,queue_obj):
self.queue_obj = queue_obj
def get_data(self):
collection = []
while self.queue_obj.empty() is False:
print("xd")
print(self.queue_obj.get(), "xd")
#I found this example in the internet(Not working)
class Threaded(QThread):
result = pyqtSignal(int)
def __init__(self, parent=None, **kwargs):
super().__init__(parent, **kwargs)
@pyqtSlot(int)
def run(self):
while True:
print("test")
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.GUI()
self.setWindowTitle("PyQt5 app")
global q
q = queue.Queue()
# BLACKSCREEN (for Test_generator)
test_generator_obj = Test_generator(q)
test_collectioner_obj = Test_collectioner(q)
t1 = threading.Thread(target=test_generator_obj.sender())
t2 = threading.Thread(target=test_collectioner_obj.get_data())
t1.start()
t2.start()
# BLACKSCREEN TOO
"""self.thread = QThread()
self.threaded = Threaded()
self.thread.started.connect(self.threaded.run())
self.threaded.moveToThread(self.thread)
qApp.aboutToQuit.connect(self.thread.quit)
self.thread.start()"""
def GUI(self):
self.showMaximized()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
您的代码中存在两个主要问题:
您正在执行线程使用的方法,但您应该使用可调用对象;你对 QThread 犯了同样的错误,因为信号的连接也需要一个可调用的,但你实际上是 执行 来自主线程的
run
函数(完全阻止一切) ,因为您使用的是括号;这些行应该是这样的:t1 = threading.Thread(target=test_generator_obj.sender)
t2 = threading.Thread(target=test_collectioner_obj.get_data)
或者,对于 QThread:
self.thread.started.connect(self.threaded.run)
由于 python GIL,多线程只会在允许的情况下将控制权释放给其他线程,但是您使用的
while
循环会阻止这种情况;添加一个小的睡眠函数确保控制周期性地返回到主线程;
还存在其他问题:
- 您已经在使用 QThread 的子类,因此使用 另一个 QThread 并将您的子类移至它是没有用的;
- 即使假设一个对象被移动到另一个线程,槽也不应该用参数修饰,因为 QThread 的
started
信号没有任何;还考虑到很少需要插槽装饰器; - 线程
quit()
只停止了线程的事件循环,但是如果run
被重写了,实际上并没有启动事件循环;如果你想停止一个带有run
实现的线程,应该使用 运行 标志来代替;在任何其他情况下,退出应用程序通常足以停止一切;
请注意,如果您想与 UI 交互,您只能使用 QThread 和自定义信号,而基本的 python 线程不提供合适的机制。
class Threaded(QThread):
result = pyqtSignal(int)
def __init__(self, parent=None, **kwargs):
super().__init__(parent, **kwargs)
def run(self):
self.keepGoing = True
while self.keepGoing:
print("test")
self.msleep(1)
def stop(self):
self.keepGoing = False
class MainWindow(QMainWindow):
def __init__(self):
# ...
self.threaded = Threaded()
self.threaded.start()
qApp.aboutToQuit.connect(self.threaded.stop)