<i id='FdsgW'><tr id='FdsgW'><dt id='FdsgW'><q id='FdsgW'><span id='FdsgW'><b id='FdsgW'><form id='FdsgW'><ins id='FdsgW'></ins><ul id='FdsgW'></ul><sub id='FdsgW'></sub></form><legend id='FdsgW'></legend><bdo id='FdsgW'><pre id='FdsgW'><center id='FdsgW'></center></pre></bdo></b><th id='FdsgW'></th></span></q></dt></tr></i><div id='FdsgW'><tfoot id='FdsgW'></tfoot><dl id='FdsgW'><fieldset id='FdsgW'></fieldset></dl></div>

    <small id='FdsgW'></small><noframes id='FdsgW'>

      • <bdo id='FdsgW'></bdo><ul id='FdsgW'></ul>
      <legend id='FdsgW'><style id='FdsgW'><dir id='FdsgW'><q id='FdsgW'></q></dir></style></legend>
      <tfoot id='FdsgW'></tfoot>

      从TKinter小部件检索/获取回命令回调函数

      时间:2024-08-11
      <tfoot id='CH5lI'></tfoot>

        <small id='CH5lI'></small><noframes id='CH5lI'>

          <bdo id='CH5lI'></bdo><ul id='CH5lI'></ul>

              <tbody id='CH5lI'></tbody>
          • <legend id='CH5lI'><style id='CH5lI'><dir id='CH5lI'><q id='CH5lI'></q></dir></style></legend>
            <i id='CH5lI'><tr id='CH5lI'><dt id='CH5lI'><q id='CH5lI'><span id='CH5lI'><b id='CH5lI'><form id='CH5lI'><ins id='CH5lI'></ins><ul id='CH5lI'></ul><sub id='CH5lI'></sub></form><legend id='CH5lI'></legend><bdo id='CH5lI'><pre id='CH5lI'><center id='CH5lI'></center></pre></bdo></b><th id='CH5lI'></th></span></q></dt></tr></i><div id='CH5lI'><tfoot id='CH5lI'></tfoot><dl id='CH5lI'><fieldset id='CH5lI'></fieldset></dl></div>

              1. 本文介绍了从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小部件检索/获取回命令回调函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                上一篇:如何在Django模板上实现返回链接(&Q;BACK&Q;LINK)? 下一篇:如何进行可以查找&Quot;最新&Quot;、最小&Quot;或&Quot;最大&

                相关文章

                  <bdo id='MaiYu'></bdo><ul id='MaiYu'></ul>

              2. <i id='MaiYu'><tr id='MaiYu'><dt id='MaiYu'><q id='MaiYu'><span id='MaiYu'><b id='MaiYu'><form id='MaiYu'><ins id='MaiYu'></ins><ul id='MaiYu'></ul><sub id='MaiYu'></sub></form><legend id='MaiYu'></legend><bdo id='MaiYu'><pre id='MaiYu'><center id='MaiYu'></center></pre></bdo></b><th id='MaiYu'></th></span></q></dt></tr></i><div id='MaiYu'><tfoot id='MaiYu'></tfoot><dl id='MaiYu'><fieldset id='MaiYu'></fieldset></dl></div>
                <tfoot id='MaiYu'></tfoot>
              3. <legend id='MaiYu'><style id='MaiYu'><dir id='MaiYu'><q id='MaiYu'></q></dir></style></legend>
              4. <small id='MaiYu'></small><noframes id='MaiYu'>