我有这个我编写的小程序,其中有一类方法,以及一个构建窗口的类(只有一个)。
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()
现在,我的问题是,当我按下按钮时,它需要做某事,然后输出应该出现在屏幕上。 但是,来了,但是 - 当动作需要一点时,它会冻结程序直到动作完成。 我想让程序将动作视为一个不同的线程,因此它不会冻结。 我尝试了一些东西但不幸的是它对我不起作用......
任何帮助? 理解!
答案 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)
希望这有帮助。