在使用tkinter進行GUI編程時,有時會碰到界面未響應的狀況,以下: python
緣由頗有多是執行的某個動做阻塞了線程,可經過使用threading.Thread解決(本例中是點擊了Go菜單下的開始選項致使的界面卡死)git
修改前代碼:github
class MenuGo(EMenu):
LABEL_GO = "Go"
LABEL_START = "開始"
LABEL_END = "終止"
def __init__(self, master=None, cnf={}, **kw):
super().__init__(master=master, cnf=cnf, **kw)
self.go = None
master.add_cascade(label=self.LABEL_GO, menu=self)
self.add_command(label=self.LABEL_START, command=self.start)
self.add_command(label=self.LABEL_END, command=self.end)
def start(self):
self.go = True
while self.go:
self.stdout("biu biu biu!", with_time=" - ")
time.sleep(1)
def end(self):
self.go = False
self.stdout("zi zi zi!", with_time=" - ")
複製代碼
修改後代碼:編程
class MenuGo(EMenu):
LABEL_GO = "Go"
LABEL_START = "開始"
LABEL_END = "終止"
def __init__(self, master=None, cnf={}, **kw):
super().__init__(master=master, cnf=cnf, **kw)
self.go = None
master.add_cascade(label=self.LABEL_GO, menu=self)
self.add_command(label=self.LABEL_START, command=self.start)
self.add_command(label=self.LABEL_END, command=self.end)
def start(self):
def run():
self.go = True
while self.go:
self.stdout("biu biu biu!", with_time=" - ")
time.sleep(1)
t = Thread(target=run)
t.start()
def end(self):
self.go = False
self.stdout("zi zi zi!", with_time=" - ")
複製代碼
from functools import wraps
from threading import Thread
class ThreadRun(object):
def __init__(self):
pass
def __call__(self, f):
@wraps(f)
def wrapped_f(*args, **kw):
t = Thread(
target=f,
args=args,
kwargs=kw
)
t.start()
return wrapped_f
複製代碼
class MenuGo(EMenu):
LABEL_GO = "Go"
LABEL_START = "開始"
LABEL_END = "終止"
def __init__(self, master=None, cnf={}, **kw):
super().__init__(master=master, cnf=cnf, **kw)
self.go = None
master.add_cascade(label=self.LABEL_GO, menu=self)
self.add_command(label=self.LABEL_START, command=self.start)
self.add_command(label=self.LABEL_END, command=self.end)
@ThreadRun()
def start(self):
self.go = True
while self.go:
self.stdout("biu biu biu!", with_time=" - ")
time.sleep(1)
def end(self):
self.go = False
self.stdout("zi zi zi!", with_time=" - ")
複製代碼
from tkinter import Menu
from tkinter import DISABLED, NORMAL
from threading import Thread
from functools import wraps
class EMenu(Menu):
def __init__(self, *args, **kw):
self.stdout = kw["stdout"] if "stdout" in kw else print
self.stderr = kw["stderr"] if "stderr" in kw else print
for key in ["stdout", "stderr"]:
if key in kw:
del kw[key]
super().__init__(*args, **kw)
def thread_run(label_name):
def run_decorator(f):
@wraps(f)
def wrapped_f(self, *args, **kw):
def call():
self.entryconfig(label_name, state=DISABLED) # 設置菜單選項禁用
f(self, *args, **kw)
self.entryconfig(label_name, state=NORMAL) # 設置菜單選項啓用
t = Thread(target=call)
t.start()
return wrapped_f
return run_decorator
複製代碼
class MenuGo(EMenu):
LABEL_GO = "Go"
LABEL_START = "開始"
LABEL_END = "終止"
def __init__(self, master=None, cnf={}, **kw):
super().__init__(master=master, cnf=cnf, **kw)
self.go = None
master.add_cascade(label=self.LABEL_GO, menu=self)
self.add_command(label=self.LABEL_START, command=self.start)
self.add_command(label=self.LABEL_END, command=self.end)
@EMenu.thread_run(LABEL_START)
def start(self):
self.go = True
while self.go:
self.stdout("biu biu biu!", with_time=" - ")
time.sleep(1)
def end(self):
self.go = False
self.stdout("zi zi zi!", with_time=" - ")
複製代碼