QThread:使用 GUI python 进行线程化
Posted
技术标签:
【中文标题】QThread:使用 GUI python 进行线程化【英文标题】:QThread: Threading with GUI python 【发布时间】:2021-02-08 14:13:10 【问题描述】:我正在制作迷你聊天应用程序来提高我在 Python 中的套接字和 GUI 技能。但是每次我启动应用程序时,我的 QThread 都会转储。 我需要使用 GUI 运行 Thread 这是 client.py
import socket
import sys
from colorama import Fore, Back, Style
from os import system, name
import sys
from chat import Ui_Form as Ui_Form
from login import Ui_Form as Ui_Form1
from PyQt5 import QtCore, QtGui, QtWidgets
from threading import Thread
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
app = QtWidgets.QApplication(sys.argv)
Form_login = QtWidgets.QWidget()
ui_login = Ui_Form1()
ui_login.setupUi(Form_login)
Form_login.show()
Form_chat = QtWidgets.QWidget()
ui_chat = Ui_Form()
ui_chat.setupUi(Form_chat)
history = ''
class listen_thread(QtCore.QObject):
running = False
listen_var = QtCore.pyqtSignal(str)
def run():
print('checkpoint')
while True:
listen_var.emit('message')
QtCore.QThread.msleep(1000)
def connect_pressed():
username = ui_login.lineEdit.text()
Form_login.hide()
Form_chat.show()
sock.connect(('127.0.0.1', 10000))
thread = QtCore.QThread()
listen1 = listen_thread()
listen1.moveToThread(thread)
listen1.listen_var.connect(update_chat_history)
thread.started.connect(listen1.run)
thread.start()
@QtCore.pyqtSlot(str)
def update_chat_history(message):
print(message)
ui_chat.textEdit_2.append(message)
def send_pressed():
message = ui_login.lineEdit.text() + ' > ' + ui_chat.lineEdit.text()
sock.send(bytes(str(message),'utf-8'))
# update_chat_history(message)
ui_chat.lineEdit.setText('')
def listen(some):
while True:
try:
data = sock.recv(1024)
except:
pass
else:
update_chat_history(str(data))
ui_login.pushButton.clicked.connect(connect_pressed)
ui_chat.pushButton.clicked.connect(send_pressed)
sys.exit(app.exec_())
当我启动它时,输出是:
QThread: Destroyed while thread is still running
Aborted (core dumped)
有人可以帮忙吗???
【问题讨论】:
【参考方案1】:您的问题的解释很简单:在connect_pressed
中创建的线程在该函数之外没有引用,因此一旦函数返回,它就会立即被垃圾收集。
“简单”的解决方案是在该函数之外创建线程并仅在那里运行线程,或者将线程添加到容器(例如,列表):
threads = []
def connect_pressed():
# ...
threads.append(thread)
但是,现实情况是,您的代码还有其他严重问题,一旦您尝试将代码扩展至最低限度,这可能会产生其他问题,这也是因为 Qt 在实现程序时更容易处理使用子类;即使 pyqtSlot
装饰器(通常是不必要的)也只有在 QObject 子类的 方法 上设置时才能正常工作。
通常不鼓励只使用匿名函数,因为它们不能直接引用必须使用的实例。另外,您的 run()
函数是错误的,因为它没有 self
参数,这将导致崩溃。
您的代码的更好版本可能与此类似:
class LoginWindow(QtWidgets.QWidget, Ui_Form1):
def __init__(self, listenThread):
super().__init__()
self.setupUi(self)
self.pushButton.clicked.connect(listenThread.start)
class ChatWindow(QtWidgets.QWidget, Ui_Form):
def __init__(self, listenThread, loginWindow):
super().__init__()
self.listenThread = listenThread
self.loginWindow = loginWindow
self.setupUi(self)
self.listenThread.listen_var.connect(self.update_chat_history)
def update_chat_history(self, message):
print(message)
self.textEdit_2.append(message)
def send_pressed(self):
message = self.loginWindow.lineEdit.text() + ' > ' + self.lineEdit.text()
sock.send(bytes(str(message),'utf-8'))
self.lineEdit.setText('')
class ListenThread(QtCore.QThread):
listen_var = QtCore.pyqtSignal(str)
def run(self):
print('checkpoint')
while True:
listen_var.emit('message')
QtCore.QThread.msleep(1000)
listenThread = ListenThread()
loginWindow = LoginWindow(listenThread)
chatWindow = ChatWindow(listenThread, loginWindow)
sys.exit(app.exec_())
【讨论】:
哦,谢谢,但是这段代码没有启动,一开始我已经放了套接字 @ДовлетКараев 显然,这只是一个摘录,并且正如解释的那样,“您的代码的更好版本可能类似于:”。您必须将我所做的与您自己的代码和所需的一切合并。 是的,抱歉我已经修复了它,这确实是我的代码的更好版本,我有最后一个问题如何隐藏登录和启动聊天。无论如何,我真的很感激谢谢!! 方法很多,视情况而定。在这个简单的例子中,由于只需要登录来启动线程,你可以将started
信号与loginWindow.hide
和chatWindow.show
连接起来。
感谢 Man U 真的帮助我理解了这个话题,世界是建立在像你这样的人之上的以上是关于QThread:使用 GUI python 进行线程化的主要内容,如果未能解决你的问题,请参考以下文章
Python Qt GUI设计:多线程中信号与槽的使用(基础篇—9)
Python Qt GUI设计:QTimer计时器类QThread多线程类和事件处理类(基础篇—8)