tkinter 输入字段自动更新

tkinter Entry Field Auto Update

每次单击鼠标左键,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

一个选择是使 LEFT_MB_Counter 成为 IntVar 可以被 Entry:

直接使用
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

您可以通过在 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

解决方案概述

问题的根源很简单,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)