【发布时间】:2021-10-17 22:40:35
【问题描述】:
在一个窗口中,我有一个按钮,单击该按钮后,我想从另一个模块执行一个方法。此方法执行时间不确定,并且取决于终端中的用户输入。此方法创建一个文件并重复打开它,将内容写入文件,然后关闭文件。在此运行的同时,我在窗口中有一个 matplotlib 图形小部件,每次通过读取和绘制文件最新行中的数据将新内容写入文件时,我想更新一个绘图。
为了检查文件的更改,我使用了 QFileSystemWatcher。现在,在 userInputFunction() 运行时没有任何反应,但是当它完成时,我得到“data/runName_Rec.txt dataFileCreated”。如果我随后以任何方式手动编辑文件,则绘图会按原样进行。因此,观察者似乎只是重新开始工作,并在 userInputFunction() 完成后看到目录发生了变化。
如何正确执行多线程,以便观察者在 userInputFunction() 运行时工作?
据我了解,如果我让它在我的 QT 程序的主线程中运行,我的应用程序中的任何内容都不会响应,直到用户输入函数完成。为了解决这个问题,我尝试按照此处的示例将用户输入法的执行移动到工作线程中:https://realpython.com/python-pyqt-qthread/。在这个工人中,我有两种方法。一个简单的使用 sleep() 的 for 循环,它需要一段时间,就像示例一样。另一个运行我的 userInputFunction()。 for 循环方法 run() 不会冻结 GUI。但是,执行我想要的实际过程的 runScan() 仍然会冻结 GUI。我不确定这里发生了什么。我不确定这是否意味着我没有正确处理线程或是否发生了其他事情。
这是我的代码相关部分的简化示例。
from PyQt5 import QtWidgets, uic, QtCore, QtGui
from pyqtgraph import PlotWidget
from PyQt5.QtCore import QObject, QThread, pyqtSignal
import pyqtgraph as pg
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QInputDialog, QLineEdit, QFileDialog, QMainWindow
import os
from os.path import exists
import csv
import numpy as np
import pandas as pd
import myModule
dirname = os.path.dirname(__file__)
# Create a worker class
class Worker(QObject):
finished = pyqtSignal()
#This works without freezing the GUI
def run(self):
"""Long-running task."""
for i in range(5):
time.sleep(1)
print("step ",i," done!")
self.finished.emit()
#This freezes the GUI
def runScan(self,param1,param2):
"""Long-running task with user input from terminal."""
myModule.userInputFunction(param1,param2)
self.finished.emit()
class someWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(someWindow, self).__init__(*args, **kwargs)
#Load the UI Page
uic.loadUi('somewindow.ui', self)
self.directoryPath = "data"
self.fs_watcher = QtCore.QFileSystemWatcher()
self.fs_watcher.addPath(self.directoryPath)
self.fs_watcher.directoryChanged.connect(self.dataFileCreated)
self.StartScanButton.clicked.connect(self.runLongTask)
self.EndScanButton.clicked.connect(self.endScan)
def dataFileCreated(self):
self.filePath = os.path.join(dirname, "data/"+ self.runNameBox.toPlainText()+"_Rec.txt")
print(self.filePath + "dataFileCreated")
self.fs_watcher.addPath(self.filePath)
self.fs_watcher.fileChanged.connect(self.update_graph)
def update_graph(self):
if exists(self.path):
print("file exists!")
#then read the filePath.txt and plots the data
else:
print("file doesn't exist yet")
def endScan(self):
#change some display things
def runLongTask(self):
# Create a QThread object
self.thread = QThread()
# Create a worker object
self.worker = Worker()
# Move worker to the thread
self.worker.moveToThread(self.thread)
# Connect signals and slots
#This results in the GUI freezing
self.thread.started.connect(self.worker.runScan(self.param1,self.param2))
#This DOES NOT result in the GUI freezing
#self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)
# Start the thread
self.thread.start()
# Final resets
self.thread.finished.connect(
lambda: print("long task done!")
)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = someWindow()
w.show()
sys.exit(app.exec_())
【问题讨论】:
标签: python multithreading pyqt5