如何将 QWidget 类中的 lineedit 字符串共享到工作线程

Posted

技术标签:

【中文标题】如何将 QWidget 类中的 lineedit 字符串共享到工作线程【英文标题】:How to share lineedit strings from a QWidget class to a worker thread 【发布时间】:2021-08-28 07:21:31 【问题描述】:

现在我有一个 GUI 窗口,它接受多行用户输入并将它们插入到来自另一个导入脚本的函数中。我需要在这个过程中添加线程,因为我插入用户输入的功能可能需要很长时间并导致 GUI 变得无响应。这个 GUI 有一个主窗口和几个继承自 QWidget 类的其他窗口。下面显示的是我的导入和接受输入的窗口的代码。

from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5.QtWidgets import QInputDialog, QFileDialog, QDialog
from PyQt5 import QtGui
from PyQt5.QtCore import Qt, QObject, QThread, pyqtSignal
import geopandas as gpd
from aw_widget import Ui_Areal_Weight
from areal_weight import arealwt

class aw(qtw.QWidget):    
    def __init__(self):
        super().__init__()
        self.ui = Ui_Areal_Weight()
        self.ui.setupUi(self)
        self.ui.aw_source_browse.clicked.connect(self.source_browser)
        self.ui.aw_target_browse.clicked.connect(self.target_browser)
        self.ui.aw_save_browse.clicked.connect(self.save_browser)
        self.ui.aw_run_prog.clicked.connect(self.run_aw)
        self.ui.aw_cancel_prog.clicked.connect(self.close_aw)
        title = "Areal Weighting Method"
        self.setWindowTitle(title)
    def source_browser(self):
        self.filename = QFileDialog.getOpenFileName()
        self.ui.aw_source_lineedit.setText(self.filename[0])  
    def target_browser(self):
        self.filename = QFileDialog.getOpenFileName()
        self.ui.aw_target_lineedit.setText(self.filename[0])    
    def save_browser(self):
        self.filename = QFileDialog.getSaveFileName()
        self.ui.aw_save_lineedit.setText(self.filename[0])              
    def run_aw(self):
        src = self.ui.aw_source_lineedit.text()
        target = self.ui.aw_target_lineedit.text()
        intp = self.ui.aw_intp_fields.text()
        intp = intp.split()
        suffix = self.ui.aw_output_suffix.text()
        save = self.ui.aw_save_lineedit.text()   
        try:
            src = gpd.read_file(src)
        except:
            qtw.QMessageBox.critical(self, 'Error', 'Invalid Source Shapefile')
            raise
        try:
            target = gpd.read_file(target)
        except:
            qtw.QMessageBox.critical(self, 'Error', 'Invalid Target Shapefile')
            raise            
        try:
            outp = arealwt(src, target, intp, suffix)
            outp.to_file(save)
            qtw.QMessageBox.information(self, 'Success', 'Areal Weighting Complete')
        except:
            qtw.QMessageBox.critical(self, 'Error', 'Interpolation Failed')
            raise                
    def close_aw(self):
        self.close()
    

界面窗口:

我的第一直觉是将 run_aw() 函数的内容移动到 aw 类之外的工作线程,但我不确定如何将 GUI 中的 lineedits 中的字符串共享给工作类,所以我可以将它们插入到我的 areawt() 函数的参数中。基本上我希望用户填写所有字段,然后当他们单击运行时,lineedit 数据被发送到工作人员类并插入到 arealwt() 函数的参数中。在我看到的 QThread 示例中,需要很长时间处理的主函数被移动到工作线程,但我还没有看到函数依赖于用户输入 GUI 的信息的示例。

我的问题是,如何将 lineedit 字符串数据从我的 GUI 窗口发送到工作线程?

【问题讨论】:

【参考方案1】:

我能够通过从我的主类发出一个信号来解决这个问题,该信号包含我想传递给工人类的变量。我在工人类的函数中添加了一个装饰器,以便它可以接受字符串作为参数。

class aw_Worker(qtc.QObject):
    finished = qtc.pyqtSignal()
    
    @qtc.pyqtSlot(str,str,list,str,str)
    def worker_func(self, src, target, intp, suffix, save):
            src = gpd.read_file(src)
            target = gpd.read_file(target)
            outp = arealwt(src, target, intp, suffix)
            outp.to_file(save)
            self.finished.emit()


class aw(qtw.QWidget): 
    worker_requested = qtc.pyqtSignal(str,str,list,str,str)

    def __init__(self):
        super().__init__()
        self.ui = Ui_Areal_Weight()
        self.ui.setupUi(self)
        self.ui.aw_source_browse.clicked.connect(self.source_browser)
        self.ui.aw_target_browse.clicked.connect(self.target_browser)
        self.ui.aw_save_browse.clicked.connect(self.save_browser)
        self.ui.aw_run_prog.clicked.connect(self.run_aw)
        self.ui.aw_cancel_prog.clicked.connect(self.close_aw)
        title = "Areal Weighting Method"
        self.setWindowTitle(title)
        
    def source_browser(self):
        self.filename = QFileDialog.getOpenFileName()
        self.ui.aw_source_lineedit.setText(self.filename[0])

    def target_browser(self):
        self.filename = QFileDialog.getOpenFileName()
        self.ui.aw_target_lineedit.setText(self.filename[0])

    def save_browser(self):
        self.filename = QFileDialog.getSaveFileName()
        self.ui.aw_save_lineedit.setText(self.filename[0]) 
     
    def run_aw(self):
        # get data from gui
        src = self.ui.aw_source_lineedit.text()
        target = self.ui.aw_target_lineedit.text()
        intp = self.ui.aw_intp_fields.text()
        intp = intp.split()
        suffix = self.ui.aw_output_suffix.text()
        save = self.ui.aw_save_lineedit.text()
        
        # create thread
        self.thread = qtc.QThread()
        # create worker
        self.worker = aw_Worker()        
        # move worker to thread
        self.worker.moveToThread(self.thread)  
        
        # connect signals and slots 
        self.worker_requested.connect(self.worker.worker_func)        
        self.worker.finished.connect(self.thread.quit)        
               
        # start thread
        self.thread.start()
        
        # send data
        self.worker_requested.emit(src,target,intp,suffix,save)

【讨论】:

以上是关于如何将 QWidget 类中的 lineedit 字符串共享到工作线程的主要内容,如果未能解决你的问题,请参考以下文章

在Qt编程在lineEdit中输入完内容后点击pushbutton并在TextBrowser显示lineEdit中的内容

QWidget类中默认是忽略inputMethodEvent事件(要获取输入的内容就必须使用这个事件)

如何从另一个 QDialog 访问组合框的文本并将其写入该对话框中的 lineEdit

强制 QWidget 结束事件传播

如何将 QMenu 中的 QAction 转换为 QWidget?

如何以编程方式更改/更新 Python PyQt4 TableView 中的数据?