Retrieve/get back command callback function from TKinter widget(从TKinter小部件检索/获取回命令回调函数)
                            本文介绍了从TKinter小部件检索/获取回命令回调函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
                        
                        问题描述
我正在(出于一些精心设计的设置原因)尝试从tkinter小部件检索实际的command回调函数,例如设置按钮的回调b
import tkinter as tk
root = tk.Tk()
b = tk.Button(root, text='btn', command=lambda:print('foo'))
两者
b['command']
b.cget('command')
我认为两者都相当于
b.tk.call(b._w, 'cget', '-command')
将仅返回类似"2277504761920<lambda>"的字符串,而不返回实际的命令函数。有没有办法获取实际的回调函数?
推荐答案
查看tkinter.__init__.py:
class BaseWidget:
    ...
    def _register(self, func, subst=None, needcleanup=1):
        """Return a newly created Tcl function. If this
        function is called, the Python function FUNC will
        be executed. An optional function SUBST can
        be given which will be executed before FUNC."""
        f = CallWrapper(func, subst, self).__call__
        name = repr(id(f))
        try:
            func = func.__func__
        except AttributeError:
            pass
        try:
            name = name + func.__name__
        except AttributeError:
            pass
        self.tk.createcommand(name, f)
        if needcleanup:
            if self._tclCommands is None:
                self._tclCommands = []
            self._tclCommands.append(name)
        return name
和
class CallWrapper:
    """Internal class. Stores function to call when some user
    defined Tcl function is called e.g. after an event occurred."""
    def __init__(self, func, subst, widget):
        """Store FUNC, SUBST and WIDGET as members."""
        self.func = func
        self.subst = subst
        self.widget = widget
    def __call__(self, *args):
        """Apply first function SUBST to arguments, than FUNC."""
        try:
            if self.subst:
                args = self.subst(*args)
            return self.func(*args)
        except SystemExit:
            raise
        except:
            self.widget._report_exception()
我们得到tkinter将函数包装在CallWrapper类中。这意味着如果我们获得所有CallWrapper对象,我们就可以恢复函数。使用@Hussic提出的猴子用更容易使用的类修补CallWrapper类的建议,我们可以轻松地获得所有CallWrapper对象。
这是我根据@Hussic的建议实施的解决方案:
import tkinter as tk
tk.call_wappers = [] # A list of all of the `MyCallWrapper` objects
class MyCallWrapper:
    __slots__ = ("func", "subst", "__call__")
    def __init__(self, func, subst, widget):
        # We aren't going to use `widget` because that can take space
        # and we have a memory leak problem
        self.func = func
        self.subst = subst
        # These are the 2 lines I added:
        # First one appends this object to the list defined up there
        # the second one uses lambda because python can be tricky if you
        # use `id(<object>.<function>)`.
        tk.call_wappers.append(self)
        self.__call__ = lambda *args: self.call(*args)
    def call(self, *args):
        """Apply first function SUBST to arguments, than FUNC."""
        try:
            if self.subst:
                args = self.subst(*args)
            return self.func(*args)
        except SystemExit:
            raise
        except:
            if tk._default_root is None:
                raise
            else:
                tk._default_root._report_exception()
tk.CallWrapper = MyCallWrapper # Monkey patch tkinter
# If we are going to monkey patch `tk.CallWrapper` why not also `tk.getcommand`?
def getcommand(name):
    for call_wapper in tk.call_wappers:
        candidate_name = repr(id(call_wapper.__call__))
        if name.startswith(candidate_name):
            return call_wapper.func
    return None
tk.getcommand = getcommand
# This is the testing code:
def myfunction():
    print("Hi")
root = tk.Tk()
button = tk.Button(root, text="Click me", command=myfunction)
button.pack()
commandname = button.cget("command")
# This is how we are going to get the function into our variable:
myfunction_from_button = tk.getcommand(commandname)
print(myfunction_from_button)
root.mainloop()
正如@Hussic在评论中所说的,列表(tk.call_wappers)只是追加了一个问题。如果您有一个.aftertkinter循环,问题就会很明显,因为每次调用.after都会将一个对象添加到列表中。要解决此问题,您可能需要使用tk.call_wappers.clear()手动清除列表。我将其更改为使用__slots__功能,以确保它不会占用大量空间,但这并不能解决问题。
这篇关于从TKinter小部件检索/获取回命令回调函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
				 沃梦达教程
				
			本文标题为:从TKinter小部件检索/获取回命令回调函数
 
				
         
 
            
        基础教程推荐
             猜你喜欢
        
	     - 求两个直方图的卷积 2022-01-01
- 无法导入 Pytorch [WinError 126] 找不到指定的模块 2022-01-01
- 修改列表中的数据帧不起作用 2022-01-01
- PermissionError: pip 从 8.1.1 升级到 8.1.2 2022-01-01
- 包装空间模型 2022-01-01
- 在同一图形上绘制Bokeh的烛台和音量条 2022-01-01
- PANDA VALUE_COUNTS包含GROUP BY之前的所有值 2022-01-01
- 在Python中从Azure BLOB存储中读取文件 2022-01-01
- Plotly:如何设置绘图图形的样式,使其不显示缺失日期的间隙? 2022-01-01
- 使用大型矩阵时禁止 Pycharm 输出中的自动换行符 2022-01-01
 
    	 
    	 
    	 
    	 
    	 
    	 
    	 
    	 
				 
				 
				 
				