|
1 | 1 | import uuid
|
| 2 | +import weakref |
2 | 3 | from contextlib import contextmanager
|
3 | 4 | import logging
|
4 | 5 | import math
|
@@ -198,14 +199,33 @@ def __init__(self, figure=None, master=None):
|
198 | 199 | # event to the window containing the canvas instead.
|
199 | 200 | # See https://wiki.tcl-lang.org/3893 (mousewheel) for details
|
200 | 201 | root = self._tkcanvas.winfo_toplevel()
|
201 |
| - root.bind("<MouseWheel>", self.scroll_event_windows, "+") |
| 202 | + |
| 203 | + # Prevent long-lived references via tkinter callback structure GH-24820 |
| 204 | + weakself = weakref.ref(self) |
| 205 | + weakroot = weakref.ref(root) |
| 206 | + |
| 207 | + def scroll_event_windows(event): |
| 208 | + self = weakself() |
| 209 | + if self is None: |
| 210 | + root = weakroot() |
| 211 | + if root is not None: |
| 212 | + root.unbind("<MouseWheel>", scroll_event_windows_id) |
| 213 | + return |
| 214 | + return self.scroll_event_windows(event) |
| 215 | + scroll_event_windows_id = root.bind("<MouseWheel>", scroll_event_windows, "+") |
202 | 216 |
|
203 | 217 | # Can't get destroy events by binding to _tkcanvas. Therefore, bind
|
204 | 218 | # to the window and filter.
|
205 | 219 | def filter_destroy(event):
|
| 220 | + self = weakself() |
| 221 | + if self is None: |
| 222 | + root = weakroot() |
| 223 | + if root is not None: |
| 224 | + root.unbind("<Destroy>", filter_destroy_id) |
| 225 | + return |
206 | 226 | if event.widget is self._tkcanvas:
|
207 | 227 | CloseEvent("close_event", self)._process()
|
208 |
| - root.bind("<Destroy>", filter_destroy, "+") |
| 228 | + filter_destroy_id = root.bind("<Destroy>", filter_destroy, "+") |
209 | 229 |
|
210 | 230 | self._tkcanvas.focus_set()
|
211 | 231 |
|
|
0 commit comments