14

My tkinter application has several controls, and I'd like to know when any changes occur to them so that I can update other parts of the application.

Is there anything that I can do short of writing an updater function, and looping at the end with:

root.after(0, updaterfunction) 

This method has worked in the past but I'm afraid that it might be expensive if there are many things to check on.

Even if I did use this method, could I save resources by only updating items with changed variables? If so, please share how, as I'm not sure how to detect specific changes outside of the update function.

nbro
  • 15,395
  • 32
  • 113
  • 196
Amarok
  • 900
  • 2
  • 7
  • 15

4 Answers4

19

Many tkinter controls can be associated with a variable. For those you can put a trace on the variable so that some function gets called whenever the variable changes.

Example:

In the following example the callback will be called whenever the variable changes, regardless of how it is changed.

def callback(*args):
    print(f"the variable has changed to '{var.get()}'")

root = tk.Tk()
var = tk.StringVar(value="one")
var.trace("w", callback)

For more information about the arguments that are passed to the callback see this answer

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
9

If you are using a Tkinter Variable class like StringVar() for storing the variables in your Tkinter OptionMenu or Checkbutton, you can use its trace() method.

trace(), basically, monitors the variable when it is read from or written to.

The trace() method takes 2 arguments - mode and function callback.

trace(mode, callback)

  • The mode argument is one of “r” (call observer when variable is read by someone), “w” (call when variable is written by someone), or “u” (undefine; call when the variable is deleted).
  • The callback argument is the call you want to make to the function when the variable is changed.

This is how it is used -

def callback(*args):
    print("variable changed!")

var = StringVar()
var.trace("w", callback)
var.set("hello")

Source : https://dafarry.github.io/tkinterbook/variable.htm

shawn1912
  • 164
  • 1
  • 2
  • 13
8

To have an event fired when a selection is made set the command option for OptionMenu

ex.

def OptionMenu_SelectionEvent(event): # I'm not sure on the arguments here, it works though
    ## do something
    pass

var = StringVar()
var.set("one")
options = ["one", "two", "three"]
OptionMenu(frame, var, *(options), command = OptionMenu_SelectionEvent).pack()
YuenFHelbig
  • 97
  • 1
  • 2
  • 3
    OptionMenu can't have a command linked to it that executes some other function in the way that a button object can have a command linked to it. OptionMenu just basically allows the user to set some variable to a predefined list (i.e. the Menu items of the OptionMenu), it then doesn't fire off some other action if you slap a "command = xxx" on it. To trigger an action off changing the selected option, you need to use a trace like Bryan states above. – Korzak Mar 10 '19 at 17:53
  • 1
    Another approach `optionMenu.bind("", optionMenuChanged)` – saeedgnu Jun 27 '19 at 15:25
  • @Korzak Did you actually try it? It works when I use it. Note that it has to come after the options tuple. Maybe it matters Python 2 vs 3... Note also that it doesn't send an event to the called function, it sends the string value that it sets the variable to. – Perkins Aug 11 '20 at 01:31
  • Except that the argument to `OptionMenu_SelectionEvent` is not an event object, but is unfortunately just a string of the current selection. @saeedgnu I wouldn't recommend using `.bind( ''`; as that only works because the optionMenu happens to [usually] change size when selecting some options, it will fail when changing between options that happen to have the same width. – Durgan Sep 09 '21 at 22:39
  • 1
    The `event` returns the text of the selected item. If the OP wants to track the index of the item for example, an extra step is required that will look for the string inside `options` and return its index. This is by no means perfect, since theoretically such a menu can have one or multiple same values. In practice doesn't make sense but it can occur if for example the menu is populated with values from a configuration file. All of this means that a custom options menu or completely custom widget is required. For most cases though getting the string of the selected item is enough. – rbaleksandar Nov 11 '21 at 15:38
  • This is easier than the trace approach in the other answers and has equivalent functionality. – Marijn Dec 14 '21 at 15:05
0

This will print the dropdown selection to the console. but my suggestion is to avoid console in GUI based applications. create a text indicator and print output to it

use the function in below code

from tkinter import *
tk = Tk()
def OptionMenu_SelectionEvent(event):
    print(var.get())
    pass
var = StringVar(); var.set("one")
options = ["one", "two", "three"]
OptionMenu(tk, var, *(options), command = OptionMenu_SelectionEvent).pack()
tk.mainloop()
Vignesh
  • 1,553
  • 1
  • 10
  • 25
  • Copy entire code and try again, it's working and the command argument is also correct @BlackJack – Vignesh Dec 17 '20 at 05:07