Python动作冻结了程序

时间:2013-10-01 20:07:32

标签: python multithreading python-2.7 tkinter threadpool

我有这个我编写的小程序,其中有一类方法,以及一个构建窗口的类(只有一个)。

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 个答案:

答案 0 :(得分:1)

可以在单独的线程中执行您的操作,但是您需要实现一个 操作时向主线程(Tk的循环正在运行)发送信号的机制 已完成,并获得结果。

一种方法是拥有一个合适的Action类,创建线程对象;你过关了 要执行的方法及其参数,然后启动线程 - 事先, 你注册了一个回调,当动作完成时,你将在你的Tk循环中调用它。 为了将结果从线程传递给回调,可以使用Queue:

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中,您只需要调用getHotFixes方法,注册即可 回调,在结束使用时对结果做一些有用的事情 register_callback并致电start()以启动Action主题:

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)

希望这有帮助。