|
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