Issue #22068: Avoided reference loops with Variables and Fonts in Tkinter.
This commit is contained in:
commit
0879001f00
|
@ -191,6 +191,7 @@ class Variable:
|
||||||
that constrain the type of the value returned from get()."""
|
that constrain the type of the value returned from get()."""
|
||||||
_default = ""
|
_default = ""
|
||||||
_tk = None
|
_tk = None
|
||||||
|
_tclCommands = None
|
||||||
def __init__(self, master=None, value=None, name=None):
|
def __init__(self, master=None, value=None, name=None):
|
||||||
"""Construct a variable
|
"""Construct a variable
|
||||||
|
|
||||||
|
@ -209,7 +210,7 @@ class Variable:
|
||||||
global _varnum
|
global _varnum
|
||||||
if not master:
|
if not master:
|
||||||
master = _default_root
|
master = _default_root
|
||||||
self._master = master
|
self._root = master._root()
|
||||||
self._tk = master.tk
|
self._tk = master.tk
|
||||||
if name:
|
if name:
|
||||||
self._name = name
|
self._name = name
|
||||||
|
@ -222,9 +223,15 @@ class Variable:
|
||||||
self.initialize(self._default)
|
self.initialize(self._default)
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
"""Unset the variable in Tcl."""
|
"""Unset the variable in Tcl."""
|
||||||
if (self._tk is not None and
|
if self._tk is None:
|
||||||
self._tk.getboolean(self._tk.call("info", "exists", self._name))):
|
return
|
||||||
|
if self._tk.getboolean(self._tk.call("info", "exists", self._name)):
|
||||||
self._tk.globalunsetvar(self._name)
|
self._tk.globalunsetvar(self._name)
|
||||||
|
if self._tclCommands is not None:
|
||||||
|
for name in self._tclCommands:
|
||||||
|
#print '- Tkinter: deleted command', name
|
||||||
|
self._tk.deletecommand(name)
|
||||||
|
self._tclCommands = None
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Return the name of the variable in Tcl."""
|
"""Return the name of the variable in Tcl."""
|
||||||
return self._name
|
return self._name
|
||||||
|
@ -244,7 +251,20 @@ class Variable:
|
||||||
|
|
||||||
Return the name of the callback.
|
Return the name of the callback.
|
||||||
"""
|
"""
|
||||||
cbname = self._master._register(callback)
|
f = CallWrapper(callback, None, self).__call__
|
||||||
|
cbname = repr(id(f))
|
||||||
|
try:
|
||||||
|
callback = callback.__func__
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
cbname = cbname + callback.__name__
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
self._tk.createcommand(cbname, f)
|
||||||
|
if self._tclCommands is None:
|
||||||
|
self._tclCommands = []
|
||||||
|
self._tclCommands.append(cbname)
|
||||||
self._tk.call("trace", "variable", self._name, mode, cbname)
|
self._tk.call("trace", "variable", self._name, mode, cbname)
|
||||||
return cbname
|
return cbname
|
||||||
trace = trace_variable
|
trace = trace_variable
|
||||||
|
@ -255,7 +275,11 @@ class Variable:
|
||||||
CBNAME is the name of the callback returned from trace_variable or trace.
|
CBNAME is the name of the callback returned from trace_variable or trace.
|
||||||
"""
|
"""
|
||||||
self._tk.call("trace", "vdelete", self._name, mode, cbname)
|
self._tk.call("trace", "vdelete", self._name, mode, cbname)
|
||||||
self._master.deletecommand(cbname)
|
self._tk.deletecommand(cbname)
|
||||||
|
try:
|
||||||
|
self._tclCommands.remove(cbname)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
def trace_vinfo(self):
|
def trace_vinfo(self):
|
||||||
"""Return all trace callback information."""
|
"""Return all trace callback information."""
|
||||||
return [self._tk.split(x) for x in self._tk.splitlist(
|
return [self._tk.split(x) for x in self._tk.splitlist(
|
||||||
|
|
|
@ -69,9 +69,10 @@ class Font:
|
||||||
**options):
|
**options):
|
||||||
if not root:
|
if not root:
|
||||||
root = tkinter._default_root
|
root = tkinter._default_root
|
||||||
|
tk = getattr(root, 'tk', root)
|
||||||
if font:
|
if font:
|
||||||
# get actual settings corresponding to the given font
|
# get actual settings corresponding to the given font
|
||||||
font = root.tk.splitlist(root.tk.call("font", "actual", font))
|
font = tk.splitlist(tk.call("font", "actual", font))
|
||||||
else:
|
else:
|
||||||
font = self._set(options)
|
font = self._set(options)
|
||||||
if not name:
|
if not name:
|
||||||
|
@ -81,21 +82,19 @@ class Font:
|
||||||
if exists:
|
if exists:
|
||||||
self.delete_font = False
|
self.delete_font = False
|
||||||
# confirm font exists
|
# confirm font exists
|
||||||
if self.name not in root.tk.splitlist(
|
if self.name not in tk.splitlist(tk.call("font", "names")):
|
||||||
root.tk.call("font", "names")):
|
|
||||||
raise tkinter._tkinter.TclError(
|
raise tkinter._tkinter.TclError(
|
||||||
"named font %s does not already exist" % (self.name,))
|
"named font %s does not already exist" % (self.name,))
|
||||||
# if font config info supplied, apply it
|
# if font config info supplied, apply it
|
||||||
if font:
|
if font:
|
||||||
root.tk.call("font", "configure", self.name, *font)
|
tk.call("font", "configure", self.name, *font)
|
||||||
else:
|
else:
|
||||||
# create new font (raises TclError if the font exists)
|
# create new font (raises TclError if the font exists)
|
||||||
root.tk.call("font", "create", self.name, *font)
|
tk.call("font", "create", self.name, *font)
|
||||||
self.delete_font = True
|
self.delete_font = True
|
||||||
# backlinks!
|
self._tk = tk
|
||||||
self._root = root
|
self._split = tk.splitlist
|
||||||
self._split = root.tk.splitlist
|
self._call = tk.call
|
||||||
self._call = root.tk.call
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
@ -120,7 +119,7 @@ class Font:
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
"Return a distinct copy of the current font"
|
"Return a distinct copy of the current font"
|
||||||
return Font(self._root, **self.actual())
|
return Font(self._tk, **self.actual())
|
||||||
|
|
||||||
def actual(self, option=None, displayof=None):
|
def actual(self, option=None, displayof=None):
|
||||||
"Return actual font attributes"
|
"Return actual font attributes"
|
||||||
|
|
|
@ -118,6 +118,8 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #22068: Avoided reference loops with Variables and Fonts in Tkinter.
|
||||||
|
|
||||||
- Issue #22165: SimpleHTTPRequestHandler now supports undecodable file names.
|
- Issue #22165: SimpleHTTPRequestHandler now supports undecodable file names.
|
||||||
|
|
||||||
- Issue #15381: Optimized line reading in io.BytesIO.
|
- Issue #15381: Optimized line reading in io.BytesIO.
|
||||||
|
|
Loading…
Reference in New Issue