问题描述
我正在用PyQt4编写我的第一个GUI应用程序,并且遇到了一个看起来很基本的问题,但是我似乎找不到一个好的答案:
I'm in the process of writing my very first GUI application with PyQt4 and I've come upon a question that seems very basic, yet I don't seem to find a good answer:
我正在使用一个线程来连续执行重复的任务,而不会阻塞主窗口.线程需要从主窗口获取一些信息(例如,旋转框的当前值),这些信息也可以在线程运行时更改.在这种情况下,在主窗口和线程之间共享此类数据的正确方法是什么?
I'm using a thread to continuously perform a repeated task without blocking the main window. The thread needs some information from the main window (e.g. the current value of a spinbox) that can also change during the runtime of the thread. In this situation, what is the proper way to share such data between the main window and the thread?
天真的,我可以提出以下可能性:
Naively, I could come up with the following possibilities:
- 将对宿主窗口的引用传递给线程,并使用它来检索所涉及变量的当前值(请参见下面的示例).
- 在线程中保留变量的副本,并通过在变量发生变化时发出信号来使其与主窗口保持同步.
- 使用全局变量.
这三个选项最有可能适用于我的特定用例(尽管2个会有些复杂),但是我觉得应该有一种更好/更多Pythonic/更多类似Qt的方式.
All three options would most likely work for my particular use case (though 2 would be a bit complicated), but I have a feeling there should be a better/more Pythonic/more Qt-like way.
这是一个最小的工作示例,说明了我想做的事情,在这种情况下,使用选项1:
Here is a minimum working example illustrating what I want to do, in this case using option 1:
from PyQt4 import QtGui, QtCore
import time, sys
class MainWindow(QtGui.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.layout = QtGui.QVBoxLayout(self)
self.spinbox = QtGui.QSpinBox(self)
self.spinbox.setValue(1)
self.layout.addWidget(self.spinbox)
self.output = QtGui.QLCDNumber(self)
self.layout.addWidget(self.output)
self.worker = Worker(self)
self.connect(self.worker, QtCore.SIGNAL('beep'), self.update)
self.worker.start()
def update(self, number):
self.output.display(number)
class Worker(QtCore.QThread):
def __init__(self, host_window):
super(Worker, self).__init__()
self.host = host_window
self.running = False
def run(self):
self.running = True
i = 0
while self.running:
i += 1
self.emit(QtCore.SIGNAL('beep'), i)
sleep_time = self.host.spinbox.value()
time.sleep(sleep_time)
def stop(self):
self.running = False
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
PS:由于我对PyQt完全没有经验,因此代码中还存在其他问题或问题不清楚的可能性不大.在这种情况下,请随时评论或编辑问题.
PS: Since I'm completely unexperienced with PyQt it's not unlikely that there are other problems with the code or the question is unclear. In this case, please feel free to comment or edit the question.
推荐答案
小部件不是线程安全的,请参见线程和QObjects :
Widgets are not thread safe, see Threads and QObjects:
并在此处查看更多定义:再入和线程安全
And see more definitions here: Reentrancy and Thread-Safety
您应仅在主线程中使用小部件,并使用信号和插槽与其他线程进行通信.
You should only use widgets in the main thread, and use signal and slots to communicate with other threads.
我认为全局变量不起作用,但是老实说,我不知道为什么.
I don't think a global variable would work, but I honestly don't know why.
在此示例中如何使用信号:
How to use signals in this example:
#in main
self.worker = Worker(self.spinbox.value())
self.worker.beep.connect(self.update)
self.spinbox.valueChanged.connect(self.worker.update_value)
class Worker(QtCore.QThread):
beep=QtCore.pyqtSignal(int)
def __init__(self,sleep_time):
super(Worker, self).__init__()
self.running = False
self.sleep_time=sleep_time
def run(self):
self.running = True
i = 0
while self.running:
i += 1
self.beep.emit(i)
time.sleep(self.sleep_time)
def stop(self):
self.running = False
def update_value(self,value):
self.sleep_time=value
注意:我使用了新型信号和插槽
NB: I use the new style signal and slots
这篇关于在PyQt中,在主窗口和线程之间共享数据的最佳方法是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!