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