2016-09-22 19 views
1

我一直在玩python大約三個月,前幾天我需要做一些卑鄙的任務(文件夾創建),我真的做了一個腳本來做到這一點。有人可以解釋如何在腳本中使用線程嗎?

出於純粹的完美主義,我想添加一個進度條,但是當我運行腳本時,它會掛起,然後在完成後說完成。我希望看到進度條達到100%而不是掛起。我讀過,我需要使用python線程來做到這一點,但我很困惑如何實現它,但也理解它。

我已經複製了理論上需要線程的代碼段。正如你所看到的,我正在使用QT Designer UI和進度條。

此外,間距不是問題。這是我第一次在Stack Overflow上發佈,所以如果我在這裏搞亂了代碼間隔,請原諒我。

非常感謝您爲我提供的任何光線。

class ShotCreator(QtGui.QDialog): 
    def __init__(self, *args): 
     ui = 'ShotCreator_UI.ui' 
     QtGui.QWidget.__init__(self, *args) 
     loadUi(ui, self) 
     self.show()  

     #Slots 

     self.connect(self.browseLocation_btn, QtCore.SIGNAL("clicked()"), self.openBrowse) 
     self.connect(self.create_btn, QtCore.SIGNAL("clicked()"), self.makeDir) 
     self.progressBar.setValue(0) 




    def makeDir(self): 
     #Get data 
     departments = self.queryValues() 
     shots = self.fullShotAmount() 
     proj = self.projName() 

     #Converting proj to string 
     proj = str(proj) 

     #Converting dirLoc to string 
     dirLoc = self.browseLocation.text() 
     dirLoc = str(dirLoc) 

     if dirLoc == "": 
      msgBox = QtGui.QMessageBox() 
      msgBox.setIcon(QMessageBox.Warning) 
      msgBox.setWindowTitle("Oops - Directory Location") 
      msgBox.setText("Please give a directory location") 
      msgBox.exec_() 


    #Creating shot numbers 
     shot = 0 
     for s in shots: 
      shot = shot + 5 
      sShot = ("00" + str(shot)) 

      if not os.path.exists(sShot): 

       #Create shot folders 
       os.mkdir(sShot) 

       self.progressBar.setValue((int(s)/int(len(shots))* 100)) 

    self.progressBar.setValue(100) 

回答

0

通常最好將你的業務邏輯出的GUI代碼,並將其放置在一個單獨的模塊,它不依賴於Qt的。這使得它更容易在另一個線程中執行它。

對於我想要進度反饋的函數,我通常會將它們轉換爲生成器。

from __future__ import division 

def makeDir(dirloc, shots): 
    cnt = len(shots) 
    #Creating shot numbers 
    shot = 0 
    for i, s in enumerate(shots): 
     shot = shot + 5 
     sShot = ("00" + str(shot)) 

     if not os.path.exists(sShot): 

      #Create shot folders 
      os.mkdir(sShot) 

     yield int((i + 1)/cnt * 100) 

創建另一個線程工人對象,將執行該業務邏輯和使用的信號報告進度回到主界面線程,從而使進度條可以更新

class Worker(QObject): 

    progress_updated = pyqtSignal(int) 
    finished = pyqtSignal() 

    @pyqtSlot(object, object) 
    def makeDir(self, dirloc, shots): 
     for progress in makeDir(dirloc, shots): 
      self.progress_updated.emit(progress) 
     self.finished.emit() 

然後添加此工人到您的GUI類並連接到信號

class ShotCreator(QtGui.QDialog): 

    start_makedirs = pyqtSignal(object, object) 

    def __init__(self, *args): 
     ui = 'ShotCreator_UI.ui' 
     QtGui.QWidget.__init__(self, *args) 
     loadUi(ui, self) 
     self.show()  

     #Slots 

     self.connect(self.browseLocation_btn, QtCore.SIGNAL("clicked()"), self.openBrowse) 
     self.connect(self.create_btn, QtCore.SIGNAL("clicked()"), self.makeDir) 
     self.progressBar.setValue(0) 

     self.thread = QThread(self) 
     self.worker = Worker(self) 
     self.worker.progress_updated.connect(self.update_progress) 
     self.worker.finished.connect(self.worker_finished) 
     self.start_makedirs.connect(self.worker.makeDir) 
     self.worker.moveToThread(self.thread) 
     self.thread.start() 

    def makeDir(self): 
     # gather information from gui 
     dirloc = '' 
     shots = [] 
     ... 
     self.start_makedirs.emit(dirloc, shots) 

    @pyqtSlot(int) 
    def update_progress(self, progress): 
     self.progressBar.setValue(progress) 

    @pyqtSlot() 
    def worker_finished(self): 
     self.progressBar.setValue(100) 
+0

感謝您的回覆!我一直在看你的反應,因爲你發佈它,也許我試圖做高級蟒蛇,當我不完全瞭解一切,但很多這使我困惑。 我不完全瞭解以下內容: '爲I,S在枚舉(張):'' 收率INT(第(i + 1)/ CNT * 100)'' @pyqtSlot(INT)' 'self.thread = QThread(self)' 'self.worker = Worker(self)' 我寫的很多內容都是從在線資源中收集的,我真的很想理解這一切。 – Nightingale

+0

第一個是python * generator *(有很多關於如何創建和使用生成器的好文章,比我在這裏給出的任何簡短解釋都要好。 '@ pyqtSlot' - Qt使用一個信號和插槽系統來在特定事件期間發送數據作爲其事件系統的一部分。從技術上講,你並不總是必須使用'pyqtSlot'來裝飾一個函數作爲一個插槽,但是你需要通過交叉線程進行通信。 –

相關問題