我正在尝试使用PySide在Python中构建一个具有多个窗口的应用程序。每个窗口执行一些函数,一个函数的执行不应该阻止其他窗口执行自己的函数,这就是我需要使用多线程的原因。但是我不知道该怎么做。我正在尝试使用新方法来使用线程(正确的),但我在网上找到的所有例子都是用C ++编写的,我不懂C ++,这就是我寻求帮助的原因。
为简化起见,我构建了两个模块,一个名为test_main
,另一个名为test_wdw
这是test_main
的代码:
import sys
import test_wdw
from PySide import QtGui
from PySide import QtCore
class Main_Window(QtGui.QMainWindow):
def __init__(self):
super(Main_Window,self).__init__()
self.initUI()
def initUI(self):
self.statusBar()
self.new_window=QtGui.QAction("&Window alpha",self)
self.new_window.triggered.connect(self.open_window)
self.menu_bar=self.menuBar()
self.menu1=self.menu_bar.addMenu('&Menu 1')
self.menu1.addAction(self.new_window)
# Creates a QMdiArea to manage all windows
self.wmanager=QtGui.QMdiArea()
self.setCentralWidget(self.wmanager)
# Shows the main window
self.showMaximized()
def open_window(self):
test_wdw.launch_window()
test_wdw.window_alpha=self.wmanager.addSubWindow(test_wdw.window)
# Shows the new window
test_wdw.window_alpha.show()
def main():
app=QtGui.QApplication(sys.argv)
main_wdw=Main_Window()
sys.exit(app.exec_())
if __name__=="__main__":
main()
这是test_wdw
的代码:
from PySide import QtGui
from PySide import QtCore
def launch_window():
global window
window=QtGui.QWidget()
window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
window.setWindowTitle('Window 1')
window.grid=QtGui.QGridLayout()
window.label=QtGui.QLabel("Hello")
window.grid.addWidget(window.label,0,0)
window.setLayout(window.grid)
window.setFixedSize(window.sizeHint())
class running_operation(QtCore.QObject):
# Function I would like to run in a separate thread
def run_operation(self):
while True:
print("hi")
myThread=QtCore.QThread()
operations = running_operation()
operations.moveToThread(myThread)
myThread.start()
我的问题是我不知道从哪里开始。我希望一旦启动新窗口,它就会在新线程中启动run_operation()
函数。
我尝试将operations.run_operation()
添加到test_wdw
文件的末尾,但发生的事情是run_operation()
在运行应用程序后立即开始执行,并且根本没有显示任何GUI。
在launch_window函数中添加operations.run_operation()
只会导致GUI崩溃。
这让我意识到run_operation
函数没有像预期的那样在单独的线程中运行。
我继续阅读文档,我相信我需要创建信号和插槽才能运行。我知道如何使用信号和插槽将QObject
连接到我希望它们在触发时执行的函数但是我不明白信号和插槽与QThread
和我有什么关系无法达到预期的结果。
我想解释一下QThread
上下文中信号和插槽的作用以及如何使用它们,我希望对我发布的代码进行更正,以便按预期运行。< / p>
其他信息:
答案 0 :(得分:2)
经过多次试验和错误以及一些C ++教程的解码后,我最终找到了自己的解决方案。
test_main
的代码保持不变。
import sys
import test_wdw
from PySide import QtGui
from PySide import QtCore
class Main_Window(QtGui.QMainWindow):
def __init__(self):
super(Main_Window,self).__init__()
self.initUI()
def initUI(self):
self.statusBar()
self.new_window=QtGui.QAction("&Window alpha",self)
self.new_window.triggered.connect(self.open_window)
self.menu_bar=self.menuBar()
self.menu1=self.menu_bar.addMenu('&Menu 1')
self.menu1.addAction(self.new_window)
# Creates a QMdiArea to manage all windows
self.wmanager=QtGui.QMdiArea()
self.setCentralWidget(self.wmanager)
# Shows the main window
self.showMaximized()
def open_window(self):
test_wdw.launch_window()
test_wdw.window_alpha=self.wmanager.addSubWindow(test_wdw.window)
# Shows the new window
test_wdw.window_alpha.show()
def main():
app=QtGui.QApplication(sys.argv)
main_wdw=Main_Window()
sys.exit(app.exec_())
if __name__=="__main__":
main()
test_wdw
的正确代码是:
from PySide import QtGui
from PySide import QtCore
def launch_window():
global window
# Creates a new window
window=QtGui.QWidget()
window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
window.setWindowTitle('Window 1')
# Creates a layout for the window and populates it with a Qlabel
window.grid=QtGui.QGridLayout()
window.label=QtGui.QLabel("Hello")
window.grid.addWidget(window.label,0,0)
# Sets the layout to the window and sets the size of the window
window.setLayout(window.grid)
window.setFixedSize(window.sizeHint())
# Starts the thread
myThread.start()
class running_operation(QtCore.QObject):
# Creates a QtCore Signal for when the operation is over (if you want something to happen when the function ends processing)
finish_operation=QtCore.Signal()
# Wraps the function to run inside a QtCore Slot (MANDATORY !)
@QtCore.Slot()
# Function I wanted to run in a separate thread ! NOW IT RUNS !
def run_operation(self):
global counter
counter=0
# Setting a timer that fires every second and calling at the same time the function print_counter()
global timer
timer=QtCore.QTimer(self)
timer.timeout.connect(self.print_counter)
timer.start(1000)
def print_counter(self):
global counter
global timer
# A random function to execute just for testing purposes, the counter keeps counting up every second.
if counter <= 3 :
counter += 1
print(counter)
elif counter == 4 :
# At seconds, we emit the finish_operation signal.
counter += 1
self.finish_operation.emit()
# At 5 seconds and more, the counter keeps counting up again every second (just to check if the thread actually exited)
else:
counter += 1
print(counter)
# Creates a new thread
myThread=QtCore.QThread()
# Creates the object "operations"
operations = running_operation()
# Moves the object to the thread
operations.moveToThread(myThread)
# Connects the QThread.started signal function to the run_operation() function.
myThread.started.connect(operations.run_operation)
# Connects the finish_operation signal to quitting the thread.
operations.finish_operation.connect(myThread.quit)
我在原始帖子(问题)中添加的所有内容都在代码注释中进行了解释。
我可以告诉函数在一个单独的线程中启动,因为GUI没有挂断。
我可以告诉线程正确退出,因为4秒后,程序不会输出任何内容。如果线程没有正确退出,并且由于我构造函数print_counter()
的方式,程序将在第二个4秒停止打印到输出,然后它将再次开始打印到输出在第5秒。
我希望有些人会觉得这很有用,可以在此基础上继续发展。