2013-10-01 112 views
0

我有這個我寫的小程序,裏面有一類方法和一個構建窗口的類(只有一個)。Python動作凍結程序

from Tkinter import * 
from tkMessageBox import * 
import socket 
import platform ,sys 
import subprocess 
from multiprocessing.pool import ThreadPool 
import Queue 
import threading 

class Methods(object): 
    def __init__(self): 
     #TODO : implement 
     pass 

    def getHostName(self): 
     try: 
      return socket.gethostname() 
     except: 
      return "ERROR :Could'nt get Hostname" 

    def getOperatingSystem(self): 
     try: 
      return platform.system() + " " + platform.release() + " " + platform.version() + " " + sys.getwindowsversion()[4] 
     except: 
      return "ERROR :Could'nt get Operating System" 

    def getHotFixes(self,queue): 
     try: 
      startupinfo = subprocess.STARTUPINFO() 
      startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 
      myProcess = subprocess.Popen(
       "wmic qfe get HotFixID, InstalledOn", 
       stdout = subprocess.PIPE, 
       stderr = subprocess.PIPE, 
       startupinfo = startupinfo) 
      out, error = myProcess.communicate() 
      full_list = out.splitlines() 
      result = "" 
      for item in full_list: 
       if item != "" and item != " ": 
        result += "%s \n" % item 

      out_number = len(result.splitlines()) - 1 
      a = "There Are %s Microsoft HotFixes Updates \n\n%s" % (out_number , result) 
      queue.put(a) 
     except: 
      return "ERROR :Could'nt get HotFixes" 


#VISUAL 
#This class will have an instance of Methods and call every action by itself. 
class MainWindow(object): 
    def __init__(self): 
     self.root = Tk() 
     self.root.title('SAAP') 
     self.root.geometry('610x440+100+100') 
     #self.root.resizable(0,0) 
     self.methods = Methods() 

     def openHostName(): 
      disableAllButtons(self) 
      result = self.methods.getHostName() 
      print result 
      self.textLabelString.set("Host Name") 
      self.textBox.config(state=NORMAL) 
      self.textBox.delete("1.0",END) 
      self.textBox.insert(INSERT,result) 
      self.textBox.config(state=DISABLED) 
      enableAllButtons(self) 

     def openOperatingSystem(): 
      disableAllButtons(self) 
      result = self.methods.getOperatingSystem() 
      print result 
      self.textLabelString.set("Operating System") 
      self.textBox.config(state=NORMAL) 
      self.textBox.delete("1.0",END) 
      self.textBox.insert(INSERT,result) 
      self.textBox.config(state=DISABLED) 
      enableAllButtons(self) 

     def openHotFixes(): 
      queue = Queue.Queue() 
      thread_ = threading.Thread(
       target = self.methods.getHotFixes, 
       name='Thread1', 
       args=[queue], 
       ) 
      thread_.start() 
      thread_.join() 
      result = queue.get() 
      disableAllButtons(self) 
      self.textLabelString.set("Microsoft Hotfixes") 
      self.textBox.config(state=NORMAL) 
      self.textBox.delete("1.0",END) 
      self.textBox.insert(INSERT,result) 
      self.textBox.config(state=DISABLED) 
      enableAllButtons(self) 



     #items decleration 
     self.actionLabel = Label(self.root, text = 'Actions',bg='blue',fg='white') 
     self.button1 = Button(self.root, text = 'Host Name' , command=openHostName) 
     self.button2 = Button(self.root, text = 'Operating System' , command = openOperatingSystem) 
     self.button3 = Button(self.root, text = 'Microsoft HotFixes' , command = openHotFixes) 
     self.button4 = Button(self.root, text = 'N4') 
     self.button5 = Button(self.root, text = 'Fi5o') 
     self.button6 = Button(self.root, text = 'C6y') 
     self.button7 = Button(self.root, text = '7') 
     self.button8 = Button(self.root, text = '8y') 
     self.button9 = Button(self.root, text = 'R9s') 
     self.button10 = Button(self.root, text = '10t') 
     self.button11 = Button(self.root, text = 'I11s') 
     self.textLabelString = StringVar() 
     self.textLabel = Label(self.root,bg='black',fg='white',width=60,textvariable=self.textLabelString) 
     self.textLabelString.set("Output") 
     self.textBox = Text(self.root,width=52) 
     self.textBox.insert(INSERT,"Here's the output") 
     self.textBox.config(state=DISABLED) 
     self.scrollBar = Scrollbar(self.root) 
     self.scrollBar.config(command=self.textBox.yview) 
     self.textBox.config(yscrollcommand=self.scrollBar.set) 

     #items placing 
     self.actionLabel.grid(row=0,column=0,sticky=W+E+N+S,pady=5) 
     self.button1.grid(row=1,column=0,padx=5,pady=5,sticky=W+E) 
     self.button2.grid(row=2,column=0,padx=5,pady=5,sticky=W+E) 
     self.button3.grid(row=3,column=0,padx=5,pady=5,sticky=W+E) 
     self.button4.grid(row=4,column=0,padx=5,pady=5,sticky=W+E) 
     self.button5.grid(row=5,column=0,padx=5,pady=5,sticky=W+E) 
     self.button6.grid(row=6,column=0,padx=5,pady=5,sticky=W+E) 
     self.button7.grid(row=7,column=0,padx=5,pady=5,sticky=W+E) 
     self.button8.grid(row=8,column=0,padx=5,pady=5,sticky=W+E) 
     self.button9.grid(row=9,column=0,padx=5,pady=5,sticky=W+E) 
     self.button10.grid(row=10,column=0,padx=5,pady=5,sticky=W+E) 
     self.button11.grid(row=11,column=0,padx=5,pady=5,sticky=W+E) 
     self.textLabel.grid(row=0,column=1,padx=10,pady=5) 
     self.textBox.grid(row=1,column=1,rowspan=11,pady=5) 
     self.scrollBar.grid(row=1,column=2,rowspan=11,sticky=N+S) 

     def disableAllButtons(self): 
      self.button1['state'] = DISABLED 
      self.button2['state'] = DISABLED 
      self.button3['state'] = DISABLED 
      self.button4['state'] = DISABLED 
      self.button5['state'] = DISABLED 
      self.button6['state'] = DISABLED 
      self.button7['state'] = DISABLED 
      self.button8['state'] = DISABLED 
      self.button9['state'] = DISABLED 
      self.button10['state'] = DISABLED 
      self.button11['state'] = DISABLED 

     def enableAllButtons(self): 
      self.button1['state'] = NORMAL 
      self.button2['state'] = NORMAL 
      self.button3['state'] = NORMAL 
      self.button4['state'] = NORMAL 
      self.button5['state'] = NORMAL 
      self.button6['state'] = NORMAL 
      self.button7['state'] = NORMAL 
      self.button8['state'] = NORMAL 
      self.button9['state'] = NORMAL 
      self.button10['state'] = NORMAL 
      self.button11['state'] = NORMAL 


def main(): 
    mainw = MainWindow() 
    mainw.root.mainloop() 

if __name__ == "__main__": 
    main() 

現在,我的問題是,當我按下一個按鈕,它需要做的東西,然後輸出應該出現在屏幕上。 但是,當動作需要一點時,它會凍結程序,直到動作完成。 我想讓程序把這個動作看作是一個不同的線程,這樣它就不會凍結。 我嘗試了一些東西,但它不能爲我工作不幸...

任何幫助? 讚賞!

回答

1

可以在單獨的線程中執行你的動作,但是當動作 完成時,你需要實現一個 信號發送到你的主線程(Tk的循環運行)的機制,並且得到結果(s) 。

一種方法是有一個適當的Action類,創建線程對象;你通過 執行的方法及其參數,然後你開始線程 - 事先, 你註冊一個回調,當你完成動作時你將會在你的Tk循環中被調用。 爲了從線程回調傳遞結果,一個隊列可以使用:

import functools 

class Action(threading.Thread): 
    def __init__(self, method, *args): 
     threading.Thread.__init__(self) 
     self.daemon = True 
     self.method=method 
     self.args=args 
     self.queue=Queue.Queue() 
    def run(self): 
     self.queue.put(self.method(*self.args)) 
    def register_callback(self, tkroot, callback): 
     # to be called by Tk's main thread, 
     # will execute the callback in the Tk main loop 
     try: 
      result = self.queue.get_nowait() 
     except: 
      # set a timer, to check again for results within 100 milliseconds 
      tkroot.after(100, functools.partial(self.register_callback, 
               tkroot, callback)) 
     else: 
      return callback(result) 

編輯:修改原始示例的,以顯示如何將此應用到getHotFixes 方法

作爲一個例子,在這裏是如何改變getHotFixes相應:

class Methods(object): 
    ... 
    def getHotFixes(self): 
     try: 
      startupinfo = subprocess.STARTUPINFO() 
      startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 
      myProcess = subprocess.Popen("wmic qfe get HotFixID, InstalledOn", 
       stdout = subprocess.PIPE, 
       stderr = subprocess.PIPE, 
       startupinfo = startupinfo) 
      out, error = myProcess.communicate() 
      full_list = out.splitlines() 
      result = "" 
      for item in full_list: 
       if item != "" and item != " ": 
       result += "%s \n" % item 

      out_number = len(result.splitlines()) - 1 
      return "There Are %s Microsoft HotFixes Updates \n\n%s" % (out_number , result) 
     except: 
      return "ERROR :Could'nt get HotFixes" 

最後,在MainWindow你只需要到c所有getHotFixes方法,註冊 回調做一些事情,結果有用時,它的使用 register_callback完成,並呼籲start()開始行動螺紋:

class MainWindow(object): 
    def __init__(self): 
     self.root = Tk() 
     ... 
     def openHotFixes(): 
      disableAllButtons(self) 
      action = Action(self.methods.getHotFixes) 
      action.register_callback(self.root, openHotFixesDone) 
      action.start() 

     def openHotFixesDone(result): 
      self.textLabelString.set("Microsoft Hotfixes") 
      self.textBox.config(state=NORMAL) 
      self.textBox.delete("1.0",END) 
      self.textBox.insert(INSERT,result) 
      self.textBox.config(state=DISABLED) 
      enableAllButtons(self) 

希望這有助於。

+0

我不明白如何實現這一成真正的方法。你能告訴我如何實現你的工作到我的方法getHotFixes()?因爲它是最重的。謝謝! –

+0

我剛剛修改了答案以顯示如何將其應用於getHotFixes。告訴我它是否有效。這些最後的變化是未經測試的,如果出現錯誤,希望你可以把它整理出來 - 你明白了。 – mguijarr

+0

不要介意我的朋友!得到它的工作!非常感謝!編輯:謝謝我得到它之前:)非常感謝! –