Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 87bbf25

Browse files
Issue #22068: Avoided reference loops with Variables and Fonts in Tkinter.
1 parent 97f17ff commit 87bbf25

3 files changed

Lines changed: 40 additions & 15 deletions

File tree

Lib/tkinter/__init__.py

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ class Variable:
191191
that constrain the type of the value returned from get()."""
192192
_default = ""
193193
_tk = None
194+
_tclCommands = None
194195
def __init__(self, master=None, value=None, name=None):
195196
"""Construct a variable
196197
@@ -209,7 +210,7 @@ def __init__(self, master=None, value=None, name=None):
209210
global _varnum
210211
if not master:
211212
master = _default_root
212-
self._master = master
213+
self._root = master._root()
213214
self._tk = master.tk
214215
if name:
215216
self._name = name
@@ -222,9 +223,15 @@ def __init__(self, master=None, value=None, name=None):
222223
self.initialize(self._default)
223224
def __del__(self):
224225
"""Unset the variable in Tcl."""
225-
if (self._tk is not None and
226-
self._tk.getboolean(self._tk.call("info", "exists", self._name))):
226+
if self._tk is None:
227+
return
228+
if self._tk.getboolean(self._tk.call("info", "exists", self._name)):
227229
self._tk.globalunsetvar(self._name)
230+
if self._tclCommands is not None:
231+
for name in self._tclCommands:
232+
#print '- Tkinter: deleted command', name
233+
self._tk.deletecommand(name)
234+
self._tclCommands = None
228235
def __str__(self):
229236
"""Return the name of the variable in Tcl."""
230237
return self._name
@@ -244,7 +251,20 @@ def trace_variable(self, mode, callback):
244251
245252
Return the name of the callback.
246253
"""
247-
cbname = self._master._register(callback)
254+
f = CallWrapper(callback, None, self).__call__
255+
cbname = repr(id(f))
256+
try:
257+
callback = callback.__func__
258+
except AttributeError:
259+
pass
260+
try:
261+
cbname = cbname + callback.__name__
262+
except AttributeError:
263+
pass
264+
self._tk.createcommand(cbname, f)
265+
if self._tclCommands is None:
266+
self._tclCommands = []
267+
self._tclCommands.append(cbname)
248268
self._tk.call("trace", "variable", self._name, mode, cbname)
249269
return cbname
250270
trace = trace_variable
@@ -255,7 +275,11 @@ def trace_vdelete(self, mode, cbname):
255275
CBNAME is the name of the callback returned from trace_variable or trace.
256276
"""
257277
self._tk.call("trace", "vdelete", self._name, mode, cbname)
258-
self._master.deletecommand(cbname)
278+
self._tk.deletecommand(cbname)
279+
try:
280+
self._tclCommands.remove(cbname)
281+
except ValueError:
282+
pass
259283
def trace_vinfo(self):
260284
"""Return all trace callback information."""
261285
return [self._tk.split(x) for x in self._tk.splitlist(

Lib/tkinter/font.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,10 @@ def __init__(self, root=None, font=None, name=None, exists=False,
6969
**options):
7070
if not root:
7171
root = tkinter._default_root
72+
tk = getattr(root, 'tk', root)
7273
if font:
7374
# get actual settings corresponding to the given font
74-
font = root.tk.splitlist(root.tk.call("font", "actual", font))
75+
font = tk.splitlist(tk.call("font", "actual", font))
7576
else:
7677
font = self._set(options)
7778
if not name:
@@ -81,21 +82,19 @@ def __init__(self, root=None, font=None, name=None, exists=False,
8182
if exists:
8283
self.delete_font = False
8384
# confirm font exists
84-
if self.name not in root.tk.splitlist(
85-
root.tk.call("font", "names")):
85+
if self.name not in tk.splitlist(tk.call("font", "names")):
8686
raise tkinter._tkinter.TclError(
8787
"named font %s does not already exist" % (self.name,))
8888
# if font config info supplied, apply it
8989
if font:
90-
root.tk.call("font", "configure", self.name, *font)
90+
tk.call("font", "configure", self.name, *font)
9191
else:
9292
# create new font (raises TclError if the font exists)
93-
root.tk.call("font", "create", self.name, *font)
93+
tk.call("font", "create", self.name, *font)
9494
self.delete_font = True
95-
# backlinks!
96-
self._root = root
97-
self._split = root.tk.splitlist
98-
self._call = root.tk.call
95+
self._tk = tk
96+
self._split = tk.splitlist
97+
self._call = tk.call
9998

10099
def __str__(self):
101100
return self.name
@@ -120,7 +119,7 @@ def __del__(self):
120119

121120
def copy(self):
122121
"Return a distinct copy of the current font"
123-
return Font(self._root, **self.actual())
122+
return Font(self._tk, **self.actual())
124123

125124
def actual(self, option=None, displayof=None):
126125
"Return actual font attributes"

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ Core and Builtins
2727
Library
2828
-------
2929

30+
- Issue #22068: Avoided reference loops with Variables and Fonts in Tkinter.
31+
3032
- Issue #22165: SimpleHTTPRequestHandler now supports undecodable file names.
3133

3234
- Issue #20729: Restored the use of lazy iterkeys()/itervalues()/iteritems()

0 commit comments

Comments
 (0)