@@ -166,6 +166,7 @@ def __init__(self, figure=None, master=None, resize_callback=None):
166166 super ().__init__ (figure )
167167 self ._idle = True
168168 self ._idle_callback = None
169+ self ._event_loop_id = None
169170 w , h = self .figure .bbox .size .astype (int )
170171 self ._tkcanvas = tk .Canvas (
171172 master = master , background = "white" ,
@@ -359,11 +360,20 @@ def flush_events(self):
359360 def start_event_loop (self , timeout = 0 ):
360361 # docstring inherited
361362 if timeout > 0 :
362- self ._master .after (int (1000 * timeout ), self .stop_event_loop )
363+ milliseconds = int (1000 * timeout )
364+ if milliseconds > 0 :
365+ self ._event_loop_id = self ._tkcanvas .after (
366+ milliseconds , self .stop_event_loop )
367+ else :
368+ self ._event_loop_id = self ._tkcanvas .after_idle (
369+ self .stop_event_loop )
363370 self ._master .mainloop ()
364371
365372 def stop_event_loop (self ):
366373 # docstring inherited
374+ if self ._event_loop_id :
375+ self ._master .after_cancel (self ._event_loop_id )
376+ self ._event_loop_id = None
367377 self ._master .quit ()
368378
369379
@@ -439,6 +449,8 @@ def destroy(*args):
439449 def destroy (self , * args ):
440450 if self .canvas ._idle_callback :
441451 self .canvas ._tkcanvas .after_cancel (self .canvas ._idle_callback )
452+ if self .canvas ._event_loop_id :
453+ self .canvas ._tkcanvas .after_cancel (self .canvas ._event_loop_id )
442454
443455 # NOTE: events need to be flushed before issuing destroy (GH #9956),
444456 # however, self.window.update() can break user code. This is the
@@ -451,7 +463,8 @@ def delayed_destroy():
451463 if self ._owns_mainloop and not Gcf .get_num_fig_managers ():
452464 self .window .quit ()
453465
454- self .window .after_idle (delayed_destroy )
466+ # "after idle after 0" avoids Tcl error/race (GH #19940)
467+ self .window .after_idle (self .window .after , 0 , delayed_destroy )
455468
456469 def get_window_title (self ):
457470 return self .window .wm_title ()
0 commit comments