2

I am trying to create a simple form using Tkinter that will do an action once a button is pressed. How do I "listen" for the button press?

I have created a callback method which will change a status variable when the button is pressed, but cannot figure out how to cause an action in my main loop once the button is pressed.

I have attempted to use a while loop (after the button is drawn) to check the value of the status variable, but when I do this, the loop executes, but my GUI elements don't appear on the screen. (If I use a for loop, they do appear, but I don't think that will work for this.)

How do I "wait" for a change in state to my "status" variable? Or is there a built-in way to do this that I am missing?

(The actual code is little more complicated - similar to the approach in the answer here (but without all the buttons being on one page) - but I think that the principle is still the same (how to listen for a change in state to one of the object variables).)

from Tkinter import * 

master = Tk()

def callback():
    status = 0
    print status

status = 1

myB = Button(text="Enter", command=callback)
myB.pack()
print status

# while True:
#   if status == 0:
#       print "button was clicked"

mainloop()
Community
  • 1
  • 1
user3092118
  • 351
  • 1
  • 3
  • 10
  • 2
    `mainloop()` start program and run till you close program. You can't use `while loop`, `sleep` or other long-running functions in Tkinter (or other GUIs) . – furas Jan 30 '16 at 23:37
  • @furas - thank you. Is there another way to "listen" for a change in the variable? – user3092118 Jan 30 '16 at 23:38
  • You can use `tkinter.IntVar` to create special object-variable a then use `trace` to call function when this object change value. – furas Jan 30 '16 at 23:49
  • you can also use `tkinter.after(time, function)` to call function repeatedly. – furas Jan 30 '16 at 23:50

1 Answers1

3

You can use after(time_ms, function_name) to call your function (but without while True) repeatedly.

import Tkinter as tk

# --- functions ---

def check():
    if status != 1:
        print 'check:', status

    # check again after 100ms
    master.after(100, check) # filename without ()

def callback():
    global status # because you use `=`

    status = 0

    print 'callback:', status

# --- main ---

status = 1

master = tk.Tk()

myB = tk.Button(master, text="Enter", command=callback)
myB.pack()

# check after 100ms
master.after(100, check) # filename without ()
# or call immediately
# check()

tk.mainloop()

Or you can use object IntVar, StringVar, etc. and trace to call function when object change value.

BTW: Label can change its text automatically when StringVar change value - it doesn't need trace for it.

import Tkinter as tk

# --- functions ---

def check(arg1, arg2, arg3): # 3 args always send by `trace`
    print 'check:', status.get() # always use `get`

def callback():
    # no needed `global status`

    status.set(0) # always use `set` instead of `=`

    print 'callback:', status.get() # always use `get`

# --- main ---

master = tk.Tk()

status = tk.IntVar() # now always use get(), set()
status.set(1)

status.trace('w', check) # w - write (`set` was used)

# use IntVar in Label 
l = tk.Label(master, textvariable=status)
l.pack()

b = tk.Button(master, text="Enter", command=callback)
b.pack()

tk.mainloop()

see: The Variable Classes (BooleanVar, DoubleVar, IntVar, StringVar)

furas
  • 134,197
  • 12
  • 106
  • 148