【问题标题】:tkinter Entry Field Auto Updatetkinter 输入字段自动更新
【发布时间】:2018-08-05 05:58:19
【问题描述】:

每单击一次鼠标左键,self.LEFT_MB_Counter 就会增加,因此值始终在变化。我希望self.LEFT_MB_Counter 中的值显示在输入字段self.left_MB_entry 中,但我无法实现。

如何让输入字段始终更新并显示self.LEFT_MB_Counter 中的当前值?

from win32api import GetKeyState
import tkinter.ttk
import tkinter


class MainApplication:
    """Class that creates the widgets and window."""
    def __init__(self, master):
        """Method that creates the class constructor."""
        self.master = master
        self.var = tkinter.IntVar(value=0)   
        self.left_MB_entry = self.Entry(self.var)
        self.left_MB_entry.grid()

    def Entry(self, text_var, justify="center"):
        """Method that defines a default entry field."""
        entry = tkinter.ttk.Entry(self.master, textvariable=text_var, justify=justify)
        return entry

class MouseCounter:
    """Class that counts mouse button clicks."""
    def __init__(self):
        """Method that creates the class constructor."""
        self.LEFT_MB = 0x01  # Virtual-key code from Microsoft for LEFT MButton
        self.Old_State_LEFT_MB = GetKeyState(self.LEFT_MB)  # LEFT MButton Down = -127 or -128, MButton Up = 0 or 1
        self.LEFT_MB_Counter = 0  # Initialize to 0

    def count(self):
        # Following block of code monitors LEFT MButton
        New_State_LEFT_MB = GetKeyState(self.LEFT_MB)
        if New_State_LEFT_MB != self.Old_State_LEFT_MB:  # Button state changed
            self.Old_State_LEFT_MB = New_State_LEFT_MB
            print(New_State_LEFT_MB)
            if New_State_LEFT_MB < 0:
                self.LEFT_MB_Counter += 1
                print("Count:", self.LEFT_MB_Counter)
                print('Left Button Pressed')
            else:
                print('Left Button Released')
        root.after(1, self.count)


root = tkinter.Tk()
root.style = tkinter.ttk.Style()
#  ('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
root.style.theme_use("clam")
APP = MainApplication(root)  # Create object instance of the user interface
root.after(0, MouseCounter().count())
root.mainloop()  # Display the user interface

【问题讨论】:

  • 这并不像你想象的那样:root.after(0, MouseCounter().count())。它立即运行MouseCounter().count(),然后安排None在零毫秒内运行。
  • 如果您想提供帮助,您应该发布回复并提供解决问题的建议……而不是仅仅试图指出问题所在。 root.after(0, MouseCounter().count()root.mainloop() 之后运行,它正在工作。它调用方法count(),在方法内部有root.after(1, self.count),它会调用自己,所以它会继续运行,这是我想要的功能,所以程序会不断地寻找鼠标点击。它正在替换我的一个 while 循环。如果您想回复,请具体说明要更改的内容和原因。谢谢。
  • "root.after(0, MouseCounter().count() 在 root.mainloop() 之后运行" - 不,它没有。() after count 使其立即运行。
  • 另一个问题:您希望这会计算系统范围内的所有点击次数,还是仅计算该程序获得焦点时发生的点击次数?
  • 仔细阅读该答案。 after(0, foo()) 立即运行 fooafter(0, foo) 安排 foo 在未来运行。看到不同?然而,这不是主要问题。

标签: python tkinter tkinter-entry


【解决方案1】:

解决方案概述

问题的根源在于MouseCounter 的实例没有引用应用程序,因此不会影响应用程序中的任何内容。这不是 tkinter 独有的,它只是一个基本的 python 原则。要更改对象,您需要对对象的引用。

一旦您确定MouseCounter 的实例引用了MainApplication 的实例,问题就变得相当容易解决了。

解决方案详情

您需要做的第一件事是将var 与条目小部件正确关联。您的代码将其作为位置参数传递,这不是正确的方法。您需要将变量分配给textvariable 属性:

    self.var = tkinter.IntVar(value=0)   
    self.left_MB_entry = self.Entry(textvariable=self.var)

接下来,您需要确保 MouseCounter 能够被传递给主应用程序的一个实例:

class MouseCounter:
    """Class that counts mouse button clicks."""
    def __init__(self, master):
        self.master = master
        ...

创建实例时,传入APP作为MainApplication的实例:

APP = MainApplication(root)
mc = MouseCounter(APP) 
root.after(0, mc.count)

接下来,您只需从您的柜台更新var

def count(self):
    ...
        if New_State_LEFT_MB < 0:
            ...
            self.master.var.set(self.LEFT_MB_Counter)
            ...

注意:您对after 的工作原理有一点误解。它不影响代码,但如果你要使用它,你应该正确使用它。

考虑这段代码:

root.after(0, MouseCounter().count())

它在功能上与以下内容相同:

result = MouseCounter().count()
root.after(0, None)

after 需要一个函数的引用,而不是实际的函数调用。您需要删除尾括号:

root.after(0, MouseCounter().count)

更好的是创建MouseCounter 的实例并保存一个引用,这样它就不会被垃圾收集器收割:

counter = MouseCounter()
root.after(0, counter.count)

【讨论】:

  • var 与 Entry 小部件正确关联。在方法条目中我有Entry(self.master, textvariable=text_var。我创建了一个MouseCounter 的实例。如您所示,我删除了括号。如您所示,我还更新了方法count,但它不起作用。谢谢你的帮助。 MouseCounter 类没有大师,这就是我认为它失败的原因。我将大师传给了班级,但仍然失败。
  • @jmm5351:我很抱歉。我已经更新了我的答案以显示如何将MainApplication 的实例传递给MouseCounter。答案的核心仍然是将变量与条目正确关联,然后更新变量。您没有正确关联变量,因为第一个位置参数是小部件的父级,而不是变量。
  • @jmm5351:我已经尝试解决您的所有问题。该解决方案在概念上非常简单,但不幸的是它需要对您的程序进行一些小改动。
  • 非常感谢您的建议和与我合作。我修复了创建默认小部件的每个方法,因此第一个位置参数是对小部件 self.master 的父级的引用。我还进行了您指定的所有其他更改,并且确实有效。
  • @BryanOakley 一个非常好的和详细的解释,对我帮助很大。恭喜
【解决方案2】:

您可以通过在MouseCounter.count() 方法中更新MainApplication 实例的名为APP.varIntVar 属性来轻松做到这一点。

这是您的代码的修改版本,展示了如何执行此操作:

from win32api import GetKeyState
import tkinter.ttk
import tkinter


class MainApplication:
    """Class that creates the widgets and window."""
    def __init__(self, master):
        """Method that creates the class constructor."""
        self.master = master
        self.var = tkinter.IntVar(value=0)
        self.left_MB_entry = self.Entry(self.var)
        self.left_MB_entry.grid()

    def Entry(self, text_var, justify="center"):
        """Method that defines a default entry field."""
        entry = tkinter.ttk.Entry(self.master, textvariable=text_var, justify=justify)
        return entry

class MouseCounter:
    """Class that counts mouse button clicks."""
    def __init__(self, variable):
        """Method that creates the class constructor."""
        self.LEFT_MB = 0x01  # Virtual-key code from Microsoft for LEFT MButton
        self.Old_State_LEFT_MB = GetKeyState(self.LEFT_MB)  # LEFT MButton Down = -127 or -128, MButton Up = 0 or 1
        self.LEFT_MB_Counter = 0  # Initialize to 0
        self.variable = variable
        self.variable.set(self.LEFT_MB_Counter)

    def count(self):
        # Following block of code monitors LEFT MButton
        New_State_LEFT_MB = GetKeyState(self.LEFT_MB)
        if New_State_LEFT_MB != self.Old_State_LEFT_MB:  # Button state changed
            self.Old_State_LEFT_MB = New_State_LEFT_MB
            print(New_State_LEFT_MB)
            if New_State_LEFT_MB < 0:
                self.LEFT_MB_Counter += 1
                self.variable.set(self.LEFT_MB_Counter)
                print("Count:", self.LEFT_MB_Counter)
                print('Left Button Pressed')
            else:
                print('Left Button Released')
        root.after(1, self.count)


root = tkinter.Tk()
root.style = tkinter.ttk.Style()
#  ('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
root.style.theme_use("clam")
APP = MainApplication(root)  # Create object instance of the user interface
mouse_counter = MouseCounter(APP.var)  # Create an instance outside of mainloop.
root.after(0, mouse_counter.count)
root.mainloop()  # Display the user interface

【讨论】:

    【解决方案3】:

    一种选择是将LEFT_MB_Counter 设为IntVarEntry 可以直接使用:

    from multiprocessing import Process, Pipe
    import time
    from win32api import GetKeyState
    import tkinter.ttk
    import tkinter
    
    
    class MainApplication(object):
        """Class that creates the widgets and window."""
        def __init__(self, master):
            """Method that creates the class constructor."""
            self.master = master
            self.mc = MouseCounter(master)
            root.after(0, self.mc.count)
            self.left_MB_entry = self.Entry(self.mc.LEFT_MB_Counter)
            self.left_MB_entry.grid()
    
    
        def Entry(self, text_var, justify="center"):
            """Method that defines a default entry field."""
            entry = tkinter.ttk.Entry(self.master, textvariable=text_var, justify=justify)
            return entry
    
    class MouseCounter:
        """Class that counts mouse button clicks."""
        def __init__(self, master):
            """Method that creates the class constructor."""
            self.master = master
            self.LEFT_MB = 0x01  # Virtual-key code from Microsoft for LEFT MButton
            self.Old_State_LEFT_MB = GetKeyState(self.LEFT_MB)  # LEFT MButton Down = -127 or -128, MButton Up = 0 or 1
            self.LEFT_MB_Counter = tkinter.IntVar(0)  # Initialize to 0
    
        def count(self):
            # Following block of code monitors LEFT MButton
            New_State_LEFT_MB = GetKeyState(self.LEFT_MB)
            if New_State_LEFT_MB != self.Old_State_LEFT_MB:  # Button state changed
                self.Old_State_LEFT_MB = New_State_LEFT_MB
                print(New_State_LEFT_MB)
                if New_State_LEFT_MB < 0:
                    self.LEFT_MB_Counter.set(self.LEFT_MB_Counter.get() + 1)
                    print("Count:", self.LEFT_MB_Counter.get())
                    print('Left Button Pressed')
                else:
                    print('Left Button Released')
            self.master.after(1, self.count)
    
    
    root = tkinter.Tk()
    root.style = tkinter.ttk.Style()
    root.style.theme_use("clam")
    APP = MainApplication(root) 
    
    root.mainloop()  # Display the user interface
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-24
      • 2012-04-03
      • 2019-07-20
      相关资源
      最近更新 更多