With every left mouse click, self.LEFT_MB_Counter
increments so the value is always changing. I want the value in self.LEFT_MB_Counter
to be displayed in the entry field self.left_MB_entry
but I'm unable to achieve this.
How can I get the entry field to always update and display the current value in 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
The root of the problem is simply that the instance of MouseCounter
has no reference to the application, and thus can't affect anything in the application. This isn't anything unique to tkinter, it's just a fundamental python principle. To change an object you need a reference to an object.
Once you make sure that the instance of MouseCounter
has a reference to the instance of MainApplication
, the problem becomes fairly trivial to solve.
The first thing you need to do is properly associate var
with the entry widget. Your code is passing it as a positional argument which is not the proper way to do it. You need to assign the variable to the textvariable
attribute:
self.var = tkinter.IntVar(value=0)
self.left_MB_entry = self.Entry(textvariable=self.var)
Next, you need to make sure that MouseCounter
is able to be passed an instance of the main application:
class MouseCounter:
"""Class that counts mouse button clicks."""
def __init__(self, master):
self.master = master
...
When you create the instance, pass in APP
as the instance of MainApplication
:
APP = MainApplication(root)
mc = MouseCounter(APP)
root.after(0, mc.count)
Next, you simply need to update var
from your counter:
def count(self):
...
if New_State_LEFT_MB < 0:
...
self.master.var.set(self.LEFT_MB_Counter)
...
Note: you have a slight misunderstanding of how after
works. It doesn't affect the code, but if you're going to use it, you should use it properly.
Consider this code:
root.after(0, MouseCounter().count())
It is functionally identical to the following:
result = MouseCounter().count()
root.after(0, None)
after
requires a reference to a function, not an actual function call. You need to remove the trailing parenthesis:
root.after(0, MouseCounter().count)
Even better would be to create the instance of MouseCounter
and save a reference so that it doesn't get reaped by the garbage collector:
counter = MouseCounter()
root.after(0, counter.count)