【发布时间】:2019-02-27 05:19:41
【问题描述】:
下面是我使用asyncio 操作tkinter 及其ttk.Progressbar() 小部件的脚本。我在参考了这些参考资料(1、2、3、4、5)后得出了它。我让进度条小部件开始工作。但我似乎无法取消(停止)负责更新tkinter.Tk() 的asyncio 任务对象,我创建该对象以替换通常的Tk() 事件mainloop()。因此,在 Tk() 窗口被销毁后,我看不到命令提示符或 >>> 提示符。 我可以或应该如何终止任务对象root.update_task?我使用的是 python 3.6。我希望loop.shutdown_asyncgens() 可以结束取消的任务,但它没有。 为什么不起作用?谢谢。
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as tkMessageBox
import time
import asyncio
INTERVAL = 0.05 #seconds
class App(ttk.Frame):
def __init__( self, master, loop, interval=0.05, *args, **kw ):
super().__init__( master,style='App.TFrame')
self.master = master
self.loop = loop
self._set_style()
self._create_widgets()
def _set_style( self ):
print( '\ndef _set_style( self ):' )
self.style = ttk.Style()
self.style.configure( 'App.TFrame', background='pink')
self.style.configure( 'sp.TFrame', background='light green')
def _create_widgets( self ):
print( '\ndef _create_widgets( self ):' )
self.sp_frame = ttk.Frame( self, style='sp.TFrame' )
self.sp_frame.grid(row=0, column=0)
#sp_frame widgets
self.sp_label1 = ttk.Label( self.sp_frame, text='SP(s):')
self.sp_combox = ttk.Combobox(
self.sp_frame, state="readonly", values=['a','b','c'] )
self.sp_combox.bind('<<ComboboxSelected>>', self._connect_esp)
self.sp_pbar = ttk.Progressbar( self.sp_frame, length=200,
mode='indeterminate',
orient=tk.HORIZONTAL, )
self.sp_label1.grid( row=0, column=0 )
self.sp_combox.grid( row=0, column=1, padx=[10,0] )
self.sp_pbar.grid( row=1, column=0, columnspan=2, sticky='ew' )
def _connect_esp( self, event):
print( '\ndef connect_esp( self, event ):' )
async def dojob( loop, start_time, duration=1 ):
print( '\nasync def dojob( loop, end_time):' )
while True:
duration = 5 #seconds
t = loop.time()
delta = t - start_time
print( 'wait time = {}'.format( delta ) )
if delta >= duration:
break
await asyncio.sleep( 1 )
return True
async def trackjob( loop ):
print( '\nasync def trackjob( loop ):' )
print( 'Job: STARTED' )
start_time = loop.time()
self.sp_pbar.start( 50 )
self.sp_pbar.update_idletasks()
result = await dojob( loop, start_time )
print( 'result = ', result, type(result) )
if result:
self.sp_pbar.stop()
self.sp_pbar.update_idletasks()
print( 'Job: ENDED' )
return True
return False
try:
future = self.loop.create_task( trackjob( self.loop ) )
print( 'future = ', future, type(future))
except syncio.CancelledError as err:
print( '_connect_esp(): future is cancelled.' )
raise
except asyncio.InvalidStateError as err:
print( '_connect_esp(): The operation is not allowed in this state..' )
raise
except asyncio.TimeoutError as err:
print( '_connect_esp(): The operation exceeded the given deadline..' )
raise
except Exception:
raise
async def tk_update( root, interval=INTERVAL ):
print( '\nasync def tk_update( interval ):' )
try:
while True:
root.update() #tk update
await asyncio.sleep( interval )
except tk.TclError as err:
print( '\nasync def tk_update( self, interval ):' )
if "application has been destroyed" not in err.args[0]:
raise
except asyncio.CancelledError as err:
print( '\nasync def tk_update( self, interval ):' )
print('Request to cancel tk_update_task received but may not be done.')
await asyncio.sleep( interval )
print( '\nasync def tk_update( interval ):' )
print( '0 Cancelled = ', root.update_task.cancelled() )
print('END of def tk_update')
def ask_quit( root, interval=INTERVAL ):
'''Confirmation to quit application.'''
print( '\ndef ask_quit( self ):' )
task=root.update_task
if tkMessageBox.askokcancel( "Quit","Quit?" ):
task.cancel()
print( '1 Cancelled = ', task.cancelled() )
root.destroy() #Destroy the Tk Window instance.
print( '2 Cancelled = ', task.cancelled() )
def main():
loop = asyncio.get_event_loop()
root = tk.Tk()
root.geometry('300x100+0+24')
root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
root.update_task = loop.create_task( tk_update( root ) )
app = App( root, loop )
app.grid(row=0, column=0, sticky='nsew')
#root.mainloop() #DO NOT IMPLEMENT; this is replaced by running
# tk's update() method in a asyncio loop called loop.
# See tk_update() method and root.update_task.
#Tell Tk window instance what to do before it is destroyed.
root.protocol("WM_DELETE_WINDOW",
lambda :ask_quit( root ) )
try:
loop.run_forever()
print('after loop.run_forever()')
finally:
loop.run_until_complete( loop.shutdown_asyncgens() )
loop.close()
print( 'Is Loop closed = ', loop.isclosed() )
if __name__ == '__main__':
main()
【问题讨论】:
-
我更正的脚本已发布here
标签: python tkinter progress-bar python-asyncio