I am trying to make a tkinter GUI that will allow the user to select a graph to display. I want this graph to be displayed when the user clicks the tkinter menu, and then if the user selects any of the menu options parts of the graph will be removed/added.
For example, in the image below, I want a graph to be displayed when the user clicks "Velocity", even if they don't click any of the options below it, "u", "v" etc.
Here is my code. As you can see I tried using postcommand, but I think I misunderstood what it does, as it doesnt work the way I want.
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
# Initial setup
super().__init__()
self.title('Class based reader')
self.minsize(800,600)
# Widgets
self.option_add('*tearOff', False)
menu_bar = tk.Menu(self)
self.config(menu = menu_bar)
velocity_menu = tk.Menu(self, postcommand = self.do_something())
menu_bar.add_cascade(label='Velocity', menu = velocity_menu)
velocity_dict= {
'u': tk.StringVar(),
'v': tk.StringVar(),
'du': tk.StringVar(),
'dv': tk.StringVar()
}
for var, check in velocity_dict.items():
velocity_menu.add_checkbutton(label = var, variable = check, onvalue = 1, offvalue = 0)
flux_menu = tk.Menu(self, postcommand = self.do_something2())
menu_bar.add_cascade(label='Momentum Flux', menu = flux_menu)
flux_dict= {
'uu': tk.StringVar(),
'uv': tk.StringVar(),
'vu': tk.StringVar(),
'vv': tk.StringVar()
}
for var, check in flux_dict.items():
flux_menu.add_checkbutton(label = var, variable = check, onvalue = 1, offvalue = 0)
pressure_menu = tk.Menu(self)
menu_bar.add_cascade(label='Pressure', menu = pressure_menu)
force_menu = tk.Menu(self)
menu_bar.add_cascade(label='Force', menu = force_menu)
analytic_menu = tk.Menu(self)
menu_bar.add_cascade(label='Compare Analytic', menu = analytic_menu)
# Run the app
self.mainloop()
def do_something(self):
print("something")
def do_something2(self):
print("something2")
App()
The problem in your code arises from how you’ve utilized the postcommand parameter during the initialization of the Menu widget. Instead of passing function references, you’re directly invoking the functions.
I would try it like this:
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
# Initial setup
super().__init__()
self.title('Class based reader')
self.minsize(800,600)
# Widgets
self.option_add('*tearOff', False)
menu_bar = tk.Menu(self)
self.config(menu=menu_bar)
velocity_menu = tk.Menu(self)
velocity_menu.add_command(label='Velocity', command=self.do_something)
menu_bar.add_cascade(label='Velocity', menu=velocity_menu)
velocity_dict = {
'u': tk.StringVar(),
'v': tk.StringVar(),
'du': tk.StringVar(),
'dv': tk.StringVar()
}
for var, check in velocity_dict.items():
velocity_menu.add_checkbutton(label=var, variable=check, onvalue=1, offvalue=0)
flux_menu = tk.Menu(self)
flux_menu.add_command(label='Momentum Flux', command=self.do_something2)
menu_bar.add_cascade(label='Momentum Flux', menu=flux_menu)
flux_dict = {
'uu': tk.StringVar(),
'uv': tk.StringVar(),
'vu': tk.StringVar(),
'vv': tk.StringVar()
}
for var, check in flux_dict.items():
flux_menu.add_checkbutton(label=var, variable=check, onvalue=1, offvalue=0)
pressure_menu = tk.Menu(self)
menu_bar.add_cascade(label='Pressure', menu=pressure_menu)
force_menu = tk.Menu(self)
menu_bar.add_cascade(label='Force', menu=force_menu)
analytic_menu = tk.Menu(self)
menu_bar.add_cascade(label='Compare Analytic', menu=analytic_menu)
# Run the app
self.mainloop()
def do_something(self):
print("Velocity menu clicked")
def do_something2(self):
print("Momentum Flux menu clicked")
App()
Removed 'postcommand' parameter from the 'Menu' widget initialization because it's not necessary for this case.
Added 'command' parameter in 'add_command' for each menu item to call the respective functions when the menu item is clicked.