我有一个包含复选框的对话框窗口,当检查每个复选框时,需要实例化一个特定的类,并在一个单独的线程上运行一个任务(每个复选框一个)。我有14个复选框来检查.isChecked()
属性,并且可以理解检查返回的布尔值是否有效并且需要更多编码。
因此我决定获取与复选框元素相对应的所有子项,只获取那些被检查的项,将它们的名称附加到列表并循环遍历它们的名称与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
我在循环中运行它之前尝试使用run_class[0].setAutoDelete(False)
但是pyQt崩溃时出现了一个小错误(我正在QGIS中运行代码)而且程序存在时很少有机会了解发生了什么。
另一方面,如果我单独运行我的类,使用if else语句检查每个复选框,那么它工作正常,我可以再次运行任务并且C ++类不会被删除,但它不是&#39 ;很好的编码方法,至少从我很少的经验来看。
是否有其他人可以建议采用不同的方法,以便在不使用太多代码的情况下顺利运行?或者知道是否有一种更有效的模式来处理这个问题,我认为这种模式一定很常见?
答案 0 :(得分:1)
您似乎应该为每个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
不起作用(假设您在启动线程池之前调用它)。我想可能存在一个错误,但如果没有一个完整的示例来测试它是不可能确定的。