2011-07-10 63 views
0

所以 - 這是我的果醬。我在Python中超級新(即幾天),並且在一個我一直運行的一組python腳本的GUI上取得了一些相當不錯的進展。它基本上建立了我的音樂收藏數據庫。當我在命令行運行它時,它的工作非常出色。我認爲這是學習python的好方法 - 爲此構建一個前端。wxPython:多線程幫助

所以 - 下面確實爲我工作。當掃描/更新按鈕在掃描開始工作時將保持「停止」狀態時,我遇到了問題。我瞭解到,是的,我需要多線程才能將STDOUT的輸出傳遞到self.LogView中。這甚至可以工作,但不是實時的。我早些時候發佈了它,並且鏈接到了網絡上的另一個教程,但我只是沒有越過這個並且越來越絕望。親愛的Stackflow.com - 讓我從瘋狂中解脫出來。如果你能做出下面的工作,那麼我可以逆向工程你至少做了什麼,因爲教程過於簡單化了,是的,我頭腦發熱。

的是在下面繁重是這樣的:

    proc = subprocess.Popen([scanCMD],shell=True,stdout=subprocess.PIPE) 
       for line in proc.stdout: 
        wx.CallAfter(self.LogWindow.AppendText(line)) 

在按鈕DEF:

def bt_ScanUpdateClick(self, event): 

周甩冰雹瑪麗

#!/usr/bin/python 
################################################################################ 
# myGUI 
################################################################################ 
# THIS WORKS, BUT DOES NOT MULTITHREAD! 
################################################################################ 

import wx 
from wxPython.wx import * 
import os 
import subprocess 
import threading 

class myGUI(wx.Frame): 

    def __init__(self, parent, title): 
     super(myGUI, self).__init__(parent, title=title, 
      size=(450, 245)) #360 for logwindow (see below) 
     panel = wx.Panel(self) 
     sizer = wx.GridBagSizer(6, 5) 
     self.currentDirectory = os.getcwd() 

    # [0] Main Database Text, Entry and Browse Button -------------------------- 
     label_MainDatabase = wx.StaticText(panel, label="Database:") 
     sizer.Add(label_MainDatabase, pos=(0, 0), flag=wx.LEFT| 
      wx.ALIGN_CENTER_VERTICAL, border=10) 

     self.tc_MainDatabase = wx.TextCtrl(panel) 
     sizer.Add(self.tc_MainDatabase, pos=(0, 1), span=(1, 4), flag=wx.TOP| 
      wx.EXPAND|wx.ALIGN_CENTER_VERTICAL) 

     bt_MainDatabase = wx.Button(panel, label="Browse...") 
     sizer.Add(bt_MainDatabase, pos=(0, 5), flag=wx.LEFT|wx.RIGHT| 
      wx.ALIGN_CENTER_VERTICAL, border=10) 
     bt_MainDatabase.Bind(wx.EVT_BUTTON, self.bt_MainDatabaseClick, 
      bt_MainDatabase) 
    # -------------------------------------------------------------------------- 
    # [1] Paths to scan for new Music ------------------------------------------ 
     self.sb_FoldersToScan = wx.StaticBox(panel, label="Folders to Scan:", size=(200,100)) 
     folderBoxSizer = wx.StaticBoxSizer(self.sb_FoldersToScan, wx.VERTICAL) 
     self.multiText = wx.TextCtrl(panel, -1,"",size=(300, 100), style=wx.TE_MULTILINE|wx.TE_READONLY) 
     self.multiText.SetInsertionPoint(0) 
     folderBoxSizer.Add(self.multiText, flag=wx.EXPAND) 
     sizer.Add(folderBoxSizer, pos=(1, 0), span=(1, 6), flag=wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, border=10) 
     bt_FoldersToScanAdd = wx.Button(panel, label="Add") 
     bt_FoldersToScanClear = wx.Button(panel, label="Clear") 
    # -------------------------------------------------------------------------- 
    # [2] Buttons to Add Folder, Clear Scan Area ------------------------------- 
     sizer.Add(bt_FoldersToScanAdd, pos=(2,0), span=(1,2), flag=wx.LEFT|wx.RIGHT| 
      wx.ALIGN_CENTER_VERTICAL, border=10) 
     bt_FoldersToScanAdd.Bind(wx.EVT_BUTTON, self.bt_FoldersToScanAddClick, bt_FoldersToScanAdd) 
     sizer.Add(bt_FoldersToScanClear, pos=(2,5), flag=wx.LEFT|wx.RIGHT| 
      wx.ALIGN_CENTER_VERTICAL, border=10) 
     bt_FoldersToScanClear.Bind(wx.EVT_BUTTON, self.bt_FoldersToScanClearClick, bt_FoldersToScanClear) 
    # -------------------------------------------------------------------------- 
    # [3] Separator line ------------------------------------------------------- 
     hl_SepLine1 = wx.StaticLine(panel, 0, (250, 50), (300,1)) 
     sizer.Add(hl_SepLine1, pos=(3, 0), span=(1, 6), flag=wx.EXPAND, border=10) 
    # -------------------------------------------------------------------------- 
    # [4] Add Scan Options and Scan Button ------------------------------------- 
     bt_ScanUpdate = wx.Button(panel, label="Scan/Update") 
     bt_ScanUpdate.Bind(wx.EVT_BUTTON, self.bt_ScanUpdateClick, bt_ScanUpdate) 
     bt_ScanRepair = wx.Button(panel, label="Repair") 
     bt_ScanRepair.Bind(wx.EVT_BUTTON, self.bt_ScanRepairClick, bt_ScanRepair) 
     self.ck_ScanVerbose = wx.CheckBox(panel, label="Verbose") 
     self.ck_ScanLog = wx.CheckBox(panel, label="Log") 
     sizer.Add(bt_ScanUpdate, pos=(4,0), span=(1,2), flag=wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, border=10) 
     sizer.Add(self.ck_ScanVerbose, pos=(4,2), flag=wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, border=10) 
     sizer.Add(self.ck_ScanLog, pos=(4,4), flag=wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, border=10) 
     sizer.Add(bt_ScanRepair, pos=(4,5), span=(1,2), flag=wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, border=10) 
    # -------------------------------------------------------------------------- 
    # [5] Separator line ------------------------------------------------------ 
     hl_SepLine2 = wx.StaticLine(panel, 0, (250, 50), (300,1)) 
     sizer.Add(hl_SepLine2, pos=(5, 0), span=(1, 6), flag=wx.EXPAND, border=10) 
    # -------------------------------------------------------------------------- 
    # [6] Output/Log Box ------------------------------------------------------- 
     self.LogWindow = wx.TextCtrl(panel, -1,"",size=(100, 100), style=wx.TE_MULTILINE|wx.TE_READONLY) 
     self.LogWindow.SetInsertionPoint(0) 
     sizer.Add(self.LogWindow, pos=(6,0), span=(1,6), flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, border=10) 

    # DEBUG 
     self.multiText.Value = "~/Network/Pictures/Test" 

     sizer.AddGrowableCol(2) 
     panel.SetSizer(sizer) 

     self.Centre() 
     self.Show() 

    def bt_MainDatabaseClick(self, event): 
     # Create a list of filters 
     filters = 'All files (*.*)|*.*|Text files (*.db)|*.db' 
     dialog = wxFileDialog (None, message = 'Select Database File...', 
      wildcard = filters, style = wxOPEN) 

     # Open Dialog Box and get Selection 
     if dialog.ShowModal() == wxID_OK: 
      selected = dialog.GetFilenames() 
      for selection in selected: 
       self.tc_MainDatabase.Value = selection 
     dialog.Destroy() 

    def bt_FoldersToScanAddClick(self, event): 
     dialog = wx.DirDialog(self, "Add a Directory...", style=wx.DD_DEFAULT_STYLE) 

     if dialog.ShowModal() == wx.ID_OK: 
      self.multiText.Value += "%s" % dialog.GetPath() + "\n" 
     dialog.Destroy() 

    def bt_FoldersToScanClearClick(self, event): 
     self.multiText.Value = "" 

    def bt_ScanUpdateClick(self, event): 
     self.SetSizeWH(450,360) 
     thread = threading.Thread() 
     thread.setDaemon(True) 
     thread.start() 

     ## DEBUG 
     self.tc_MainDatabase.Value = "test.db" 

     if self.tc_MainDatabase.Value == "": 
      self.LogWindow.Value += "ERROR:\tNo database name selected!\n" 
     else: 
      scanCMD = "./scan -d " + self.tc_MainDatabase.Value + " " 

      numLines=0 
      maxLines=(int(self.multiText.GetNumberOfLines())) 

      if self.multiText.GetLineText(numLines) == "": 
       self.LogWindow.Value += "ERROR\tNo folder selected to scan!\n" 
      else: 
       self.LogWindow.Value += "Running Scan...\n\n" 
       while (numLines < maxLines): 
        scanCMD += str(self.multiText.GetLineText(numLines)) + " " 
        numLines += 1 

       self.LogWindow.Value += scanCMD 

       proc = subprocess.Popen([scanCMD],shell=True,stdout=subprocess.PIPE) 
       for line in proc.stdout: 
        wx.CallAfter(self.LogWindow.AppendText(line)) 

#    p = subprocess.Popen([scanCMD],shell=True,stdout=subprocess.PIPE) 
#    self.LogWindow.Value += p.stdout.readline() 

    def bt_ScanRepairClick(self, event): 
     print "Repair clicked" 

if __name__ == '__main__': 
    app = wx.App() 
    myGUI(None, title="myGUI") 

    app.MainLoop() 

回答

0

我從來沒有必要將我的線程設置爲守護進程。實際上,我只有Thread類。我不是一個線程專家,所以我建議看http://wiki.wxpython.org/LongRunningTasks並嘗試其中的一種方法或使用我在此使用的方法:http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/我已經多次使用後者,沒有任何問題。否則,你應該交給官方的wxPython用戶組,那裏有一些非常有知識的人,我相信你可以幫助你。

+0

想一想我的工作 - 謝謝邁克。 :)現在我無法讓STDOUT在線程中正常工作,但看起來*線程*部分正在工作。 – chow