mirror of
https://github.com/python/cpython
synced 2024-09-16 01:21:09 +00:00
Issue #22115: Added methods trace_add, trace_remove and trace_info in the
tkinter.Variable class. They replace old methods trace_variable, trace, trace_vdelete and trace_vinfo that use obsolete Tcl commands and might not work in future versions of Tcl.
This commit is contained in:
parent
523ccd135c
commit
8122174af1
|
@ -391,6 +391,19 @@ telnetlib
|
|||
Stéphane Wirtel in :issue:`25485`).
|
||||
|
||||
|
||||
tkinter
|
||||
-------
|
||||
|
||||
Added methods :meth:`~tkinter.Variable.trace_add`,
|
||||
:meth:`~tkinter.Variable.trace_remove` and :meth:`~tkinter.Variable.trace_info`
|
||||
in the :class:`tkinter.Variable` class. They replace old methods
|
||||
:meth:`~tkinter.Variable.trace_variable`, :meth:`~tkinter.Variable.trace`,
|
||||
:meth:`~tkinter.Variable.trace_vdelete` and
|
||||
:meth:`~tkinter.Variable.trace_vinfo` that use obsolete Tcl commands and might
|
||||
not work in future versions of Tcl.
|
||||
(Contributed by Serhiy Storchaka in :issue:`22115`).
|
||||
|
||||
|
||||
typing
|
||||
------
|
||||
|
||||
|
|
|
@ -465,24 +465,24 @@ def CreatePageGeneral(self):
|
|||
return frame
|
||||
|
||||
def AttachVarCallbacks(self):
|
||||
self.fontSize.trace_variable('w', self.VarChanged_font)
|
||||
self.fontName.trace_variable('w', self.VarChanged_font)
|
||||
self.fontBold.trace_variable('w', self.VarChanged_font)
|
||||
self.spaceNum.trace_variable('w', self.VarChanged_spaceNum)
|
||||
self.colour.trace_variable('w', self.VarChanged_colour)
|
||||
self.builtinTheme.trace_variable('w', self.VarChanged_builtinTheme)
|
||||
self.customTheme.trace_variable('w', self.VarChanged_customTheme)
|
||||
self.themeIsBuiltin.trace_variable('w', self.VarChanged_themeIsBuiltin)
|
||||
self.highlightTarget.trace_variable('w', self.VarChanged_highlightTarget)
|
||||
self.keyBinding.trace_variable('w', self.VarChanged_keyBinding)
|
||||
self.builtinKeys.trace_variable('w', self.VarChanged_builtinKeys)
|
||||
self.customKeys.trace_variable('w', self.VarChanged_customKeys)
|
||||
self.keysAreBuiltin.trace_variable('w', self.VarChanged_keysAreBuiltin)
|
||||
self.winWidth.trace_variable('w', self.VarChanged_winWidth)
|
||||
self.winHeight.trace_variable('w', self.VarChanged_winHeight)
|
||||
self.startupEdit.trace_variable('w', self.VarChanged_startupEdit)
|
||||
self.autoSave.trace_variable('w', self.VarChanged_autoSave)
|
||||
self.encoding.trace_variable('w', self.VarChanged_encoding)
|
||||
self.fontSize.trace_add('write', self.VarChanged_font)
|
||||
self.fontName.trace_add('write', self.VarChanged_font)
|
||||
self.fontBold.trace_add('write', self.VarChanged_font)
|
||||
self.spaceNum.trace_add('write', self.VarChanged_spaceNum)
|
||||
self.colour.trace_add('write', self.VarChanged_colour)
|
||||
self.builtinTheme.trace_add('write', self.VarChanged_builtinTheme)
|
||||
self.customTheme.trace_add('write', self.VarChanged_customTheme)
|
||||
self.themeIsBuiltin.trace_add('write', self.VarChanged_themeIsBuiltin)
|
||||
self.highlightTarget.trace_add('write', self.VarChanged_highlightTarget)
|
||||
self.keyBinding.trace_add('write', self.VarChanged_keyBinding)
|
||||
self.builtinKeys.trace_add('write', self.VarChanged_builtinKeys)
|
||||
self.customKeys.trace_add('write', self.VarChanged_customKeys)
|
||||
self.keysAreBuiltin.trace_add('write', self.VarChanged_keysAreBuiltin)
|
||||
self.winWidth.trace_add('write', self.VarChanged_winWidth)
|
||||
self.winHeight.trace_add('write', self.VarChanged_winHeight)
|
||||
self.startupEdit.trace_add('write', self.VarChanged_startupEdit)
|
||||
self.autoSave.trace_add('write', self.VarChanged_autoSave)
|
||||
self.encoding.trace_add('write', self.VarChanged_encoding)
|
||||
|
||||
def remove_var_callbacks(self):
|
||||
"Remove callbacks to prevent memory leaks."
|
||||
|
@ -493,7 +493,7 @@ def remove_var_callbacks(self):
|
|||
self.keyBinding, self.builtinKeys, self.customKeys,
|
||||
self.keysAreBuiltin, self.winWidth, self.winHeight,
|
||||
self.startupEdit, self.autoSave, self.encoding,):
|
||||
var.trace_vdelete('w', var.trace_vinfo()[0][1])
|
||||
var.trace_remove('write', var.trace_info()[0][1])
|
||||
|
||||
def VarChanged_font(self, *params):
|
||||
'''When one font attribute changes, save them all, as they are
|
||||
|
|
|
@ -343,16 +343,9 @@ def set(self, value):
|
|||
def get(self):
|
||||
"""Return value of variable."""
|
||||
return self._tk.globalgetvar(self._name)
|
||||
def trace_variable(self, mode, callback):
|
||||
"""Define a trace callback for the variable.
|
||||
|
||||
MODE is one of "r", "w", "u" for read, write, undefine.
|
||||
CALLBACK must be a function which is called when
|
||||
the variable is read, written or undefined.
|
||||
|
||||
Return the name of the callback.
|
||||
"""
|
||||
f = CallWrapper(callback, None, self).__call__
|
||||
def _register(self, callback):
|
||||
f = CallWrapper(callback, None, self._root).__call__
|
||||
cbname = repr(id(f))
|
||||
try:
|
||||
callback = callback.__func__
|
||||
|
@ -366,25 +359,99 @@ def trace_variable(self, mode, callback):
|
|||
if self._tclCommands is None:
|
||||
self._tclCommands = []
|
||||
self._tclCommands.append(cbname)
|
||||
return cbname
|
||||
|
||||
def trace_add(self, mode, callback):
|
||||
"""Define a trace callback for the variable.
|
||||
|
||||
Mode is one of "read", "write", "unset", or a list or tuple of
|
||||
such strings.
|
||||
Callback must be a function which is called when the variable is
|
||||
read, written or unset.
|
||||
|
||||
Return the name of the callback.
|
||||
"""
|
||||
cbname = self._register(callback)
|
||||
self._tk.call('trace', 'add', 'variable',
|
||||
self._name, mode, (cbname,))
|
||||
return cbname
|
||||
|
||||
def trace_remove(self, mode, cbname):
|
||||
"""Delete the trace callback for a variable.
|
||||
|
||||
Mode is one of "read", "write", "unset" or a list or tuple of
|
||||
such strings. Must be same as were specified in trace_add().
|
||||
cbname is the name of the callback returned from trace_add().
|
||||
"""
|
||||
self._tk.call('trace', 'remove', 'variable',
|
||||
self._name, mode, cbname)
|
||||
for m, ca in self.trace_info():
|
||||
if self._tk.splitlist(ca)[0] == cbname:
|
||||
break
|
||||
else:
|
||||
self._tk.deletecommand(cbname)
|
||||
try:
|
||||
self._tclCommands.remove(cbname)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def trace_info(self):
|
||||
"""Return all trace callback information."""
|
||||
splitlist = self._tk.splitlist
|
||||
return [(splitlist(k), v) for k, v in map(splitlist,
|
||||
splitlist(self._tk.call('trace', 'info', 'variable', self._name)))]
|
||||
|
||||
def trace_variable(self, mode, callback):
|
||||
"""Define a trace callback for the variable.
|
||||
|
||||
MODE is one of "r", "w", "u" for read, write, undefine.
|
||||
CALLBACK must be a function which is called when
|
||||
the variable is read, written or undefined.
|
||||
|
||||
Return the name of the callback.
|
||||
|
||||
This deprecated method wraps a deprecated Tcl method that will
|
||||
likely be removed in the future. Use trace_add() instead.
|
||||
"""
|
||||
# TODO: Add deprecation warning
|
||||
cbname = self._register(callback)
|
||||
self._tk.call("trace", "variable", self._name, mode, cbname)
|
||||
return cbname
|
||||
|
||||
trace = trace_variable
|
||||
|
||||
def trace_vdelete(self, mode, cbname):
|
||||
"""Delete the trace callback for a variable.
|
||||
|
||||
MODE is one of "r", "w", "u" for read, write, undefine.
|
||||
CBNAME is the name of the callback returned from trace_variable or trace.
|
||||
|
||||
This deprecated method wraps a deprecated Tcl method that will
|
||||
likely be removed in the future. Use trace_remove() instead.
|
||||
"""
|
||||
# TODO: Add deprecation warning
|
||||
self._tk.call("trace", "vdelete", self._name, mode, cbname)
|
||||
self._tk.deletecommand(cbname)
|
||||
try:
|
||||
self._tclCommands.remove(cbname)
|
||||
except ValueError:
|
||||
pass
|
||||
cbname = self._tk.splitlist(cbname)[0]
|
||||
for m, ca in self.trace_info():
|
||||
if self._tk.splitlist(ca)[0] == cbname:
|
||||
break
|
||||
else:
|
||||
self._tk.deletecommand(cbname)
|
||||
try:
|
||||
self._tclCommands.remove(cbname)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def trace_vinfo(self):
|
||||
"""Return all trace callback information."""
|
||||
"""Return all trace callback information.
|
||||
|
||||
This deprecated method wraps a deprecated Tcl method that will
|
||||
likely be removed in the future. Use trace_info() instead.
|
||||
"""
|
||||
# TODO: Add deprecation warning
|
||||
return [self._tk.splitlist(x) for x in self._tk.splitlist(
|
||||
self._tk.call("trace", "vinfo", self._name))]
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Comparison for equality (==).
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import unittest
|
||||
|
||||
import gc
|
||||
from tkinter import (Variable, StringVar, IntVar, DoubleVar, BooleanVar, Tcl,
|
||||
TclError)
|
||||
|
||||
|
@ -87,6 +87,105 @@ def test_initialize(self):
|
|||
v.set("value")
|
||||
self.assertTrue(v.side_effect)
|
||||
|
||||
def test_trace_old(self):
|
||||
# Old interface
|
||||
v = Var(self.root)
|
||||
vname = str(v)
|
||||
trace = []
|
||||
def read_tracer(*args):
|
||||
trace.append(('read',) + args)
|
||||
def write_tracer(*args):
|
||||
trace.append(('write',) + args)
|
||||
cb1 = v.trace_variable('r', read_tracer)
|
||||
cb2 = v.trace_variable('wu', write_tracer)
|
||||
self.assertEqual(sorted(v.trace_vinfo()), [('r', cb1), ('wu', cb2)])
|
||||
self.assertEqual(trace, [])
|
||||
|
||||
v.set('spam')
|
||||
self.assertEqual(trace, [('write', vname, '', 'w')])
|
||||
|
||||
trace = []
|
||||
v.get()
|
||||
self.assertEqual(trace, [('read', vname, '', 'r')])
|
||||
|
||||
trace = []
|
||||
info = sorted(v.trace_vinfo())
|
||||
v.trace_vdelete('w', cb1) # Wrong mode
|
||||
self.assertEqual(sorted(v.trace_vinfo()), info)
|
||||
with self.assertRaises(TclError):
|
||||
v.trace_vdelete('r', 'spam') # Wrong command name
|
||||
self.assertEqual(sorted(v.trace_vinfo()), info)
|
||||
v.trace_vdelete('r', (cb1, 43)) # Wrong arguments
|
||||
self.assertEqual(sorted(v.trace_vinfo()), info)
|
||||
v.get()
|
||||
self.assertEqual(trace, [('read', vname, '', 'r')])
|
||||
|
||||
trace = []
|
||||
v.trace_vdelete('r', cb1)
|
||||
self.assertEqual(v.trace_vinfo(), [('wu', cb2)])
|
||||
v.get()
|
||||
self.assertEqual(trace, [])
|
||||
|
||||
trace = []
|
||||
del write_tracer
|
||||
gc.collect()
|
||||
v.set('eggs')
|
||||
self.assertEqual(trace, [('write', vname, '', 'w')])
|
||||
|
||||
trace = []
|
||||
del v
|
||||
gc.collect()
|
||||
self.assertEqual(trace, [('write', vname, '', 'u')])
|
||||
|
||||
def test_trace(self):
|
||||
v = Var(self.root)
|
||||
vname = str(v)
|
||||
trace = []
|
||||
def read_tracer(*args):
|
||||
trace.append(('read',) + args)
|
||||
def write_tracer(*args):
|
||||
trace.append(('write',) + args)
|
||||
tr1 = v.trace_add('read', read_tracer)
|
||||
tr2 = v.trace_add(['write', 'unset'], write_tracer)
|
||||
self.assertEqual(sorted(v.trace_info()), [
|
||||
(('read',), tr1),
|
||||
(('write', 'unset'), tr2)])
|
||||
self.assertEqual(trace, [])
|
||||
|
||||
v.set('spam')
|
||||
self.assertEqual(trace, [('write', vname, '', 'write')])
|
||||
|
||||
trace = []
|
||||
v.get()
|
||||
self.assertEqual(trace, [('read', vname, '', 'read')])
|
||||
|
||||
trace = []
|
||||
info = sorted(v.trace_info())
|
||||
v.trace_remove('write', tr1) # Wrong mode
|
||||
self.assertEqual(sorted(v.trace_info()), info)
|
||||
with self.assertRaises(TclError):
|
||||
v.trace_remove('read', 'spam') # Wrong command name
|
||||
self.assertEqual(sorted(v.trace_info()), info)
|
||||
v.get()
|
||||
self.assertEqual(trace, [('read', vname, '', 'read')])
|
||||
|
||||
trace = []
|
||||
v.trace_remove('read', tr1)
|
||||
self.assertEqual(v.trace_info(), [(('write', 'unset'), tr2)])
|
||||
v.get()
|
||||
self.assertEqual(trace, [])
|
||||
|
||||
trace = []
|
||||
del write_tracer
|
||||
gc.collect()
|
||||
v.set('eggs')
|
||||
self.assertEqual(trace, [('write', vname, '', 'write')])
|
||||
|
||||
trace = []
|
||||
del v
|
||||
gc.collect()
|
||||
self.assertEqual(trace, [('write', vname, '', 'unset')])
|
||||
|
||||
|
||||
class TestStringVar(TestBase):
|
||||
|
||||
|
|
|
@ -10,6 +10,11 @@ What's New in Python 3.6.0 alpha 3
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #22115: Added methods trace_add, trace_remove and trace_info in the
|
||||
tkinter.Variable class. They replace old methods trace_variable, trace,
|
||||
trace_vdelete and trace_vinfo that use obsolete Tcl commands and might
|
||||
not work in future versions of Tcl.
|
||||
|
||||
- Issue #26243: Only the level argument to zlib.compress() is keyword argument
|
||||
now. The first argument is positional-only.
|
||||
|
||||
|
|
Loading…
Reference in a new issue