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