我需要创建一个像 StringVar 这样的变量,但又像一个列表的列表(行/列表)。我阅读了 tkinter 文件并找到了一个名为“Variable”的类,所有其他类都继承了该类。我尝试制作自己的变量,但我的 IDE 给我一个错误。在 Lib 文件的类变量中,变量创建两个类变量:“_tk”和“_name”。但是当我从这个类继承时,我的 IDE 告诉我:
类“ListVar”的未解析属性引用“_tk”
与“_name”相同的问题。
源代码:
class Variable:
"""Class to define value holders for e.g. buttons.
Subclasses StringVar, IntVar, DoubleVar, BooleanVar are specializations
that constrain the type of the value returned from get()."""
_default = ""
_tk = None
_tclCommands = None
def __init__(self, master=None, value=None, name=None):
"""Construct a variable
MASTER can be given as master widget.
VALUE is an optional value (defaults to "")
NAME is an optional Tcl name (defaults to PY_VARnum).
If NAME matches an existing variable and VALUE is omitted
then the existing value is retained.
"""
# check for type of NAME parameter to override weird error message
# raised from Modules/_tkinter.c:SetVar like:
# TypeError: setvar() takes exactly 3 arguments (2 given)
if name is not None and not isinstance(name, str):
raise TypeError("name must be a string")
global _varnum
if not master:
master = _default_root
self._root = master._root()
self._tk = master.tk
if name:
self._name = name
else:
self._name = 'PY_VAR' + repr(_varnum)
_varnum += 1
if value is not None:
self.initialize(value)
elif not self._tk.getboolean(self._tk.call("info", "exists", self._name)):
self.initialize(self._default)
def __del__(self):
"""Unset the variable in Tcl."""
if self._tk is None:
return
if self._tk.getboolean(self._tk.call("info", "exists", 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):
"""Return the name of the variable in Tcl."""
return self._name
def set(self, value):
"""Set the variable to VALUE."""
return self._tk.globalsetvar(self._name, value)
initialize = set
def get(self):
"""Return value of variable."""
return self._tk.globalgetvar(self._name)
def _register(self, callback):
f = CallWrapper(callback, None, self._root).__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)
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)
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.
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 (==).
Note: if the Variable's master matters to behavior
also compare self._master == other._master
"""
return self.__class__.__name__ == other.__class__.__name__ \
and self._name == other._name
StringVar 源代码:
class StringVar(Variable):
"""Value holder for strings variables."""
_default = ""
def __init__(self, master=None, value=None, name=None):
"""Construct a string variable.
MASTER can be given as master widget.
VALUE is an optional value (defaults to "")
NAME is an optional Tcl name (defaults to PY_VARnum).
If NAME matches an existing variable and VALUE is omitted
then the existing value is retained.
"""
Variable.__init__(self, master, value, name)
def get(self):
"""Return value of variable as string."""
value = self._tk.globalgetvar(self._name)
if isinstance(value, str):
return value
return str(value)
我的源代码:
from tkinter import Variable
from typing import Optional
class ListVar(Variable):
_default = []
def __init__(self, master=None, value: Optional[list] = None, name: Optional[str] = None):
"""Construct a string variable.
MASTER can be given as master widget.
VALUE is an optional value (defaults to empty list)
NAME is an optional Tcl name (defaults to PY_VARnum).
If NAME matches an existing variable and VALUE is omitted
then the existing value is retained.
"""
Variable.__init__(self, master, value, name)
def get(self):
"""Return value of variable as string."""
value = self._tk.globalgetvar(self._name)
if isinstance(value, str):
return value
return str(value)