2015-09-25 51 views
1

我有一個包含複選框的對話窗口,當他們每個都被選中時,一個特定的類需要被實例化並且在一個單獨的線程上運行一個任務(每個複選框一個)。我有14個複選框來檢查.isChecked()屬性,並且可理解地檢查返回的布爾值,因爲它們中的每一個都不是高效的,並且需要更多的編碼。Pyqt和一般的python,這可以被認爲是一種正確的編碼方法嗎?

因此,我決定讓所有對應於複選框元素的子項目,只取得那些被選中的元素,將它們的名字附加到列表中,並通過它們匹配它們的名稱到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個任務執行相同類型的功能。這些函數的參數是包含報告靜態內容的其他字典和返回報告主要動態內容的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++類不會被刪除,但它不是被刪除的,但它不是'至少從我很少的經驗來看,這是一種很好的編碼方法。

有沒有其他人可以建議不同的方法,以使這個運行順利,而不使用太多的代碼行?或者知道是否有更高效的模式來處理這個問題,我認爲這一點很常見?

+0

似乎你以某種方式失去了你的對象引用。如果在循環結束時將'self.summary_runnables = {key:鍵的值,self.summary_runnables.items()}中的值'放在循環的結尾處,可以嘗試嗎? –

+0

你能告訴我你在哪裏使用我的代碼並使用我使用的變量名稱來放這段代碼嗎? – user3523583

+0

在你的循環中'self.long_task.start(run_class [0])'後面加'self.summary_runnables = {key:key,value in self.summary_runnables.items()}'的值。 –

回答

1

看來你應該創建每個可運行的新實例,並允許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不起作用(假設你調用它之前啓動線程池)。我想可能會有一個錯誤,但是如果沒有一個完整的工作示例來測試它是不可能的。

+0

建議的解決方案的工作原理,但正如你所說,代碼中肯定存在一個錯誤,但不容易找到14個不同的線程,雖然(對我來說)。當我將autodelete設置爲False時,代碼在最後崩潰。它正確執行所有線程,然後崩潰。線程池運行線程,調用線程所在模塊中的其他全局函數,傳遞參數並將結果寫入文件。我會按照以下方式發佈代碼,如果你想看一看,並告訴我,如果你發現一些不完全正確的東西。 – user3523583

+0

@ user3523583。如果你使用'setAutoDelete(False)',你必須保留一個引用(因爲Qt並不擁有對象的所有權) - 但是看起來你並沒有爲'start_report'和'end_report'這樣做。 – ekhumoro

+0

我評論了這些行,因爲它讓我的代碼崩潰了,但是如果你假裝這些行沒有被評論,那麼在開始和結束報告可運行類的實例化之後,我嘗試設置autodelete屬性。我可以問,究竟「保持參考」是什麼意思?感謝您的幫助 – user3523583

相關問題