您好我试图了解pyqt5中的线程。我概述了我目前使用的过程。这是正确的方法还是有更好的方法?注意,我是一个完整的穿线菜鸟。
这是我从GUI对象传递数据的方式。例如组合框已更改,我在GUI类中有一个self.comboBox.activated.connect(comboBoxChanged),然后相应的函数设置SharedVars.comboBoxChanged = True然后在其中一个threadloops中检查并查看SharedVars.comboBoxChanged = = True,如果是,则执行self.updateOtherStuffWhenComboBoxChanged.emit(getData())和SharedVars.comboBoxChanged = False
class SharedVars():
...
#This is my GUI class
class Ui_MainWindow(QThread, SharedVars):
def setupUi(self, MainWindow):
#self.table stuff
#this is the class i start threads, get a response and update the GUI
class MainUIClass(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__()
self.setupUi(self)
self.threadclass = ThreadClass()
self.threadclass.start()
self.threadclass.updateTable.connect(self.updateTable)
self.threadclass2 = ThreadClass2()
self.threadclass2.start()
self.threadclass2.etc.connect(self.etc)
def updateTable(self, val):
#print("update self.table stuff")
def etc(self, val):
#print("update other stuff on gui")
#my first thread. If i have network calls that block i use several threads
class ThreadClass(QtCore.QThread, SharedVars):
updateTable = pyqtSignal(list)
def __init__(self, parent=None):
super().__init__()
def run(self):
def getData():
...
return [data]
while True:
self.updateTable.emit(getData())
#my second thread
class ThreadClass2(QtCore.QThread, SharedVars):
etc = pyqtSignal(list)
def __init__(self, parent=None):
super().__init__()
def run(self):
def getData():
...
return [data]
while True:
self.etc.emit(getData())
if __name__ == "__main__":
a = QtWidgets.QApplication(sys.argv)
app = MainUIClass()
app.show()
sys.exit(a.exec_())
也许有更好的方法。也许我可以直接从GUI对象发送信号到例如线程类。
编辑:好的,所以“three_pineapples”向我展示了一个例子,我转换为qt5,更改了一些术语,否则改变了一点。我也删除了装饰器,因为我无法让它们与qt5一起工作,我不知道这是不是一个坏主意(虽然它似乎仍然有效):
from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtCore import pyqtSignal, QThread, QTimer
import time
import sys
class MyTask(QtCore.QObject):
disableBtn = pyqtSignal()
enableBtn = pyqtSignal()
def firstTask(self):
self.disableBtn.emit()
print('oooh so much processing...')
time.sleep(4)
print('phew, finished!')
self.enableBtn.emit()
class Window(QtWidgets.QWidget):
def __init__(self, parent = None):
super().__init__()
self.initUi()
self.setupThread()
def initUi(self):
layout = QtWidgets.QVBoxLayout()
self.button = QtWidgets.QPushButton('Click Me')
layout.addWidget(self.button)
self.setLayout(layout)
self.show()
def enableBtn(self):
self.button.setEnabled(True)
def disableBtn(self):
self.button.setEnabled(False)
def setupThread(self):
self.thread = QThread()
self.task = MyTask()
self.task.moveToThread(self.thread)
#self.thread.started.connect(self.task.firstTask)
self.button.clicked.connect(self.task.firstTask)
self.task.disableBtn.connect(self.disableBtn)
self.task.enableBtn.connect(self.enableBtn)
# Start thread
self.thread.start()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Window()
app.exec_()
有人在您发布的链接中谈到了内存问题。我会经常从DB更新3个表元素,这是我需要担心的吗?另外,time.sleep()的用法。我听说有人不应该使用带有线程的time.sleep()吗?也许我可以使用QThread.msleep?
答案 0 :(得分:0)
我不确定线程是否正确,但我非常有信心不需要它。 Qt的主要优势之一是基于事件。程序员连接各个组件之间的信号和插槽,以定义当某些事件发生时,您希望应用程序表现的方式。
在您发布的代码中,您正在运行这些后台线程,其唯一的工作似乎是充当GUI中事件(按钮点击)和其他逻辑之间的中间人(更新一些表,发网络请求)。只需将按钮单击时发出的信号直接连接到您想要的功能即可。
你有:
clicked --> thread makes network request --> thread emits signal with reply -->
GUI receives data from thread signals and does some more work.
做类似的事情要简单得多:
clicked --> make network request --> respond to network reply
所有这一切都可能发生在主线程中,Qt将以异步方式执行所有网络I / O,以便不阻止应用程序的其余部分(例如GUI)。
例如,您可以更新主窗口以包含两个用于发出网络请求并处理响应的插槽,并将这些插槽直接连接到按钮单击信号。所以,它可能看起来像这样:
#!/usr/bin/env python3
import sys
from PyQt5 import QtWidgets, QtCore, QtNetwork
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.nam = QtNetwork.QNetworkAccessManager(self)
self.push_button = QtWidgets.QPushButton("Make request", self)
self.setCentralWidget(self.push_button)
# When button is pressed, make network request
self.push_button.clicked.connect(self.make_request)
# When reply is received, do "work".
self.nam.finished.connect(self.handle_reply)
QtCore.pyqtSlot()
def make_request(self):
request = QtNetwork.QNetworkRequest(QtCore.QUrl("http://www.google.com"))
self.nam.head(request)
QtCore.pyqtSlot(QtNetwork.QNetworkReply)
def handle_reply(self, reply):
# This just prints the status code, but you can have
# this slot update the GUI, change some data structure,
# or emit another signal.
print('Status code:',
reply.attribute(QtNetwork.QNetworkRequest.HttpStatusCodeAttribute))
reply.deleteLater()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
这都是假设您正在发出HTTP请求。如果您使用较低级别的协议而不是TCP,则需要QtNetwork.QTcpSocket
,并且您使用QTcpSocket.readyRead()
信号而不是{{1}信号。