Pyqt和通用python,这可以被认为是正确的编码方法吗?

Pyqt和通用python,这可以被认为是正确的编码方法吗?,python,design-patterns,pyqt,Python,Design Patterns,Pyqt,我有一个包含复选框的对话框窗口,当选中每个复选框时,需要实例化一个特定的类,并在一个单独的线程上运行一个任务(每个复选框对应一个)。我有14个复选框来检查.isChecked()属性,并且可以理解为每个属性检查返回的布尔值效率不高,需要更多的编码 因此,我决定获取与复选框元素对应的所有子项,只获取被选中的子项,将它们的名称添加到列表中,并将它们的名称与d字典相匹配,d字典的键是复选框的名称,值是要实例化的对应类 示例: # class dictionary self.summary_

我有一个包含复选框的对话框窗口,当选中每个复选框时,需要实例化一个特定的类,并在一个单独的线程上运行一个任务(每个复选框对应一个)。我有14个复选框来检查
.isChecked()
属性,并且可以理解为每个属性检查返回的布尔值效率不高,需要更多的编码

因此,我决定获取与复选框元素对应的所有子项,只获取被选中的子项,将它们的名称添加到列表中,并将它们的名称与d字典相匹配,d字典的键是复选框的名称,值是要实例化的对应类

示例:

# class dictionary 

    self.summary_runnables = {'dupStreetCheckBox': [DupStreetDesc(),0],
                              'notStreetEsuCheckBox': [StreetsNoEsuDesc(),1],
                              'notType3CheckBox': [Type3Desc(False),2],
                              'incFootPathCheckBox': [Type3Desc(True),2],
                              'dupEsuRefCheckBox': [DupEsuRef(True),3],
                              'notEsuStreetCheckBox': [NoLinkEsuStreets(),4],
                              'invCrossRefCheckBox': [InvalidCrossReferences()],
                              'startEndCheckBox': [CheckStartEnd(tol=10),8],
                              'tinyEsuCheckBox': [CheckTinyEsus("esu",1)],
                              'notMaintReinsCheckBox': [CheckMaintReins()],
                              'asdStartEndCheckBox': [CheckAsdCoords()],
                              'notMaintPolysCheckBox': [MaintNoPoly(),16],
                              'notPolysMaintCheckBox': [PolyNoMaint()],
                              'tinyPolysCheckBox': [CheckTinyEsus("rd_poly",1)]}


# looping through list
    self.long_task = QThreadPool(None).globalInstance()
    self.long_task.setMaxThreadCount(1)
    start_report = StartReport(val_file_path)
    end_report = EndReport()
    # start_report.setAutoDelete(False)
    # end_report.setAutoDelete(False)
    end_report.signals.result.connect(self.log_progress)
    end_report.signals.finished.connect(self.show_finished)
    # end_report.setAutoDelete(False)
    start_report.signals.result.connect(self.log_progress)
    self.long_task.start(start_report)
    # print str(self.check_boxes_names)
    for check_box_name in self.check_boxes_names:
        run_class = self.summary_runnables[check_box_name]
        if run_class[0].__class__.__name__ is 'CheckStartEnd':
            run_class[0].tolerance = tolerance
        runnable = run_class[0]()
        runnable.signals.result.connect(self.log_progress)
        self.long_task.start(runnable)
    self.long_task.start(end_report)
可运行函数的示例(即使其中一些函数使用不同的全局函数)

我不能发布将内容写入文件的全局函数,因为它们太多,并且不是所有14个任务都执行相同类型的函数。这些函数的参数是其他字典的int键,这些字典包含报表静态内容和返回报表主动态内容的SQL查询

class StartReport(QRunnable):

    def __init__(self, file_path):
        super(StartReport,self).__init__()
        # open the db connection in thread
        db.open()
        self.signals = GeneralSignals()
        # self.simple_signal = SimpleSignal()
        # print self.signals.result
        self.file_path = file_path
        self.task = "Starting Report"
        self.progress = 1
        self.org_name = org_name
        self.user = user
        self.report_title = "Validation Report"
        print "instantiation of start report "

    def run(self):
        self.signals.result.emit(self.task, self.progress)
        if self.file_path is None:
            print "I started and found file none "
            return
        else:
            global report_file
            # create the file and prints the header
            report_file = open(self.file_path, 'wb')
            report_file.write(str(self.report_title) + ' for {0} \n'.format(self.org_name))
            report_file.write('Created on : {0} at {1} By : {2} \n'.format(datetime.today().strftime("%d/%m/%Y"),
                                                                                datetime.now().strftime("%H:%M"),
                                                                                str(self.user)))
            report_file.write(
                "------------------------------------------------------------------------------------------ \n \n \n \n")
            report_file.flush()
            os.fsync(report_file.fileno())


class EndReport(QRunnable):

    def __init__(self):
        super(EndReport,self).__init__()
        self.signals = GeneralSignals()
        self.task = "Finishing report"
        self.progress = 100


    def run(self):
        self.signals.result.emit(self.task, self.progress)
        if report_file is not None:
            # write footer and close file
            report_file.write("\n \n \n")
            report_file.write("---------- End of Report -----------")
            report_file.flush()
            os.fsync(report_file.fileno())
            report_file.close()
            self.signals.finished.emit()
            # TODO: checking whether opening a db connection in thread might affect the db on the GUI
            # if db.isOpen():
            #     db.close()
        else:
            return


class DupStreetDesc(QRunnable):
    """
    duplicate street description report section creation
    :return: void if the report is to text
            list[string] if the report is to screen
    """
    def __init__(self):
        super(DupStreetDesc,self).__init__()
        self.signals = GeneralSignals()
        self.task = "Checking duplicate street descriptions..."
        self.progress = 16.6

    def run(self):
        self.signals.result.emit(self.task,self.progress)
        if report_file is None:
            print "report file is none "
            # items_list = write_content(0, 0, 0, 0)
            # for item in items_list:
                 # self.signals.list.emit(item)
        else:
            write_content(0, 0, 0, 0)
现在,我以前使用过这种方法,并且它在不使用多处理的情况下一直工作良好。在这种情况下,它在某种程度上运行良好,我可以第一次运行任务,但如果我尝试第二次运行,则会出现以下Python错误:

self.long_task.start(run_class[0])
RuntimeError: wrapped C/C++ object of type DupStreetDesc has been deleted
在循环中运行它们之前,我尝试使用
运行类[0]。setAutoDelete(False)
,但是pyQt由于一个小转储错误而崩溃(我在QGIS中运行代码),并且我认为程序存在,几乎没有机会理解发生了什么

另一方面,如果我单独运行我的类,用IF语句检查每个复选框,那么它就可以正常工作,我可以再次运行任务,C++类不会被删除,但它不是一个好的编码方法,至少从我的经验来看。


有没有其他人可以建议一种不同的方法,以便在不使用太多代码行的情况下顺利运行?或者知道是否有一种更有效的模式来处理这个问题,我认为这一定很常见?

似乎应该为每个runnable创建一个新实例,并允许Qt自动删除它。因此,您的词典条目可能如下所示:

    'dupStreetCheckBox': [lambda: DupStreetDesc(), 0],
然后你可以做:

for check_box_name in self.check_boxes_names:
    run_class = self.summary_runnables[check_box_name]
    runnable = run_class[0]()
    runnable.signals.result.connect(self.log_progress)
    self.long_task.start(runnable)

我不知道为什么
setAutoDelete
不起作用(假设您在启动线程池之前调用它)。我想可能有一个bug,但如果没有一个完整的工作示例进行测试,就不可能确定。

似乎不知何故丢失了对象引用。如果将
self.summary\u runnables={key:value-for-key,value-in-self.summary\u-runnables.items()}
放在循环的末尾有帮助,请告诉我使用我的代码和我使用的变量名将代码放在哪里?请将
self.summary\u runnables={key:value for key,value in self.summary\u runnables.items()}
就在循环中的
self.long\u task.start(run\u class[0])
之后。建议的解决方案是可行的,但正如您所说,代码中肯定有一个bug,但在14个不同的线程中不容易找到(对我来说)。当我将autodelete设置为False时,代码最终崩溃。它正确执行所有线程,然后崩溃。线程池运行线程,这些线程调用线程所在模块中的其他全局函数,传递参数并将结果写入文件。如果您想看一看,我将按如下方式发布代码,如果您愿意,请告诉我找出不完全正确的地方。@user3523583。如果使用
setAutoDelete(False)
,则必须保留一个引用(因为Qt不拥有对象的所有权)-但您似乎没有为
start\u report
end\u report
这样做。我对这些行进行了注释,因为这会使我的代码崩溃,但如果您假装这些行没有注释,则在开始和结束report可运行类安装之后,我尝试设置自动删除属性。请问,“保留参考资料”到底是什么意思?谢谢helping@user3523583.我假设您问题中的第一段代码是方法的一部分,因此
start\u report
end\u report
在超出范围时(即方法返回时)将被垃圾收集。因此,您需要类似于
self.end\u report=EndReport()
的内容来阻止这种情况的发生(或者您可以将它们与所有其他可运行项一起保存在字典中)。如果我将autodelete设置为False,则代码会崩溃,如果我不处理代码,则每次都会重新创建类。Start和End是唯一不属于循环的类,如果我不将autodelete设置为False(这意味着执行后应将其删除),则每次代码运行时都会重新创建它们(就在setMaxThreadCount(1)之后)。我仍然不明白为什么autodelete=False会使一切都中断。您的解决方案有效,但我更希望了解到底。