如何将列表对象从 QThread 线程发送到 UI 的主线程?
How can I send a list object from a QThread thread to the UI's main thread?
我编写了这个示例代码来尝试弄清楚如何在后台线程和主线程之间进行通信。据我了解,线程不能简单地与 UI 或不同线程中存在的变量进行交互。
我想在后台线程中抓取列表 'data',然后在 UI 中的 'lbl2' 上显示它。如果这个程序是运行原样,它会在命令行打印我想要的结果。
Data received in background thread = [1, 2, 3, 4, 5]
Q1:从后台线程向主线程发送列表或字符串等数据的正确方法是什么?
问题 2:我将如何开始在示例代码中实现它?
#!/usr/bin/env python3.4
from PySide.QtGui import QPushButton, QApplication, QWidget, QLabel
from PySide.QtCore import QThread, QCoreApplication
import queue
import sys
class Gui(QWidget):
def __init__(self):
super(Gui, self).__init__()
self.initUI()
def initUI(self):
lbl1 = QLabel('Data Recieved =', self)
lbl2 = QLabel('None', self)
lbl2.move(85, 0)
lbl2.resize(100, 15)
qbtn = QPushButton('Quit', self)
qbtn.clicked.connect(QCoreApplication.instance().quit)
qbtn.move(0, 20)
btn = QPushButton('Get Summary', self)
btn.move(100, 20)
btn.clicked.connect(lambda: bgThread.summary())
self.setGeometry(300, 300, 200, 50)
self.setWindowTitle('Thread Communication Example')
self.show()
class BackgroundThread(QThread):
def __init__(self, q, loop_time=1.0/60):
self.q = q
self.timeout = loop_time
super(BackgroundThread, self).__init__()
def onThread(self, function, *args, **kwargs):
self.q.put((function, args, kwargs))
def run(self):
while True:
try:
function, args, kwargs = self.q.get(timeout=self.timeout)
function(*args, **kwargs)
except queue.Empty:
self.idle()
def idle(self):
pass
def _summary(self):
# Run function which will return a list object
# data = externalclass.summary()
# Need to send list:'data' to the main thread.
data = [1, 2, 3, 4, 5]
print('Data received in background thread =', data)
def summary(self):
self.onThread(self._summary)
if __name__ == "__main__":
app = QApplication(sys.argv)
# Setup background thread
request_queue = queue.Queue()
bgThread = BackgroundThread(request_queue)
bgThread.start()
# Setup Gui
ui = Gui()
sys.exit(app.exec_())
您可以定义一个自定义信号,它可以安全地跨线程发射:
from PySide.QtCore import Signal
class Gui(QWidget):
def initUI(self):
...
bgThread.dataReceived.connect(lambda data: lbl2.setText(str(data)))
class BackgroundThread(QThread):
dataReceived = Signal(list)
...
def _summary(self):
...
self.dataReceived.emit(data)
我编写了这个示例代码来尝试弄清楚如何在后台线程和主线程之间进行通信。据我了解,线程不能简单地与 UI 或不同线程中存在的变量进行交互。
我想在后台线程中抓取列表 'data',然后在 UI 中的 'lbl2' 上显示它。如果这个程序是运行原样,它会在命令行打印我想要的结果。
Data received in background thread = [1, 2, 3, 4, 5]
Q1:从后台线程向主线程发送列表或字符串等数据的正确方法是什么?
问题 2:我将如何开始在示例代码中实现它?
#!/usr/bin/env python3.4
from PySide.QtGui import QPushButton, QApplication, QWidget, QLabel
from PySide.QtCore import QThread, QCoreApplication
import queue
import sys
class Gui(QWidget):
def __init__(self):
super(Gui, self).__init__()
self.initUI()
def initUI(self):
lbl1 = QLabel('Data Recieved =', self)
lbl2 = QLabel('None', self)
lbl2.move(85, 0)
lbl2.resize(100, 15)
qbtn = QPushButton('Quit', self)
qbtn.clicked.connect(QCoreApplication.instance().quit)
qbtn.move(0, 20)
btn = QPushButton('Get Summary', self)
btn.move(100, 20)
btn.clicked.connect(lambda: bgThread.summary())
self.setGeometry(300, 300, 200, 50)
self.setWindowTitle('Thread Communication Example')
self.show()
class BackgroundThread(QThread):
def __init__(self, q, loop_time=1.0/60):
self.q = q
self.timeout = loop_time
super(BackgroundThread, self).__init__()
def onThread(self, function, *args, **kwargs):
self.q.put((function, args, kwargs))
def run(self):
while True:
try:
function, args, kwargs = self.q.get(timeout=self.timeout)
function(*args, **kwargs)
except queue.Empty:
self.idle()
def idle(self):
pass
def _summary(self):
# Run function which will return a list object
# data = externalclass.summary()
# Need to send list:'data' to the main thread.
data = [1, 2, 3, 4, 5]
print('Data received in background thread =', data)
def summary(self):
self.onThread(self._summary)
if __name__ == "__main__":
app = QApplication(sys.argv)
# Setup background thread
request_queue = queue.Queue()
bgThread = BackgroundThread(request_queue)
bgThread.start()
# Setup Gui
ui = Gui()
sys.exit(app.exec_())
您可以定义一个自定义信号,它可以安全地跨线程发射:
from PySide.QtCore import Signal
class Gui(QWidget):
def initUI(self):
...
bgThread.dataReceived.connect(lambda data: lbl2.setText(str(data)))
class BackgroundThread(QThread):
dataReceived = Signal(list)
...
def _summary(self):
...
self.dataReceived.emit(data)