Is it possible to change the label of an item in a menu with tkinter?
In the following example, I'd like to change it from "An example item" (in the "File" menu) to a different value.
from tkinter import *
root = Tk()
menu_bar = Menu(root)
file_menu = Menu(menu_bar, tearoff=False)
file_menu.add_command(label="An example item", command=lambda: print('clicked!'))
menu_bar.add_cascade(label="File", menu=file_menu)
root.config(menu=menu_bar)
root.mainloop()
I found the solution myself in the Tcl manpages:
Use the entryconfigure() method like so, which changes the value after it has been clicked:
The first parameter 1 has to be the index of the item you want to change, starting from 1.
from tkinter import *
root = Tk()
menu_bar = Menu(root)
def clicked(menu):
menu.entryconfigure(1, label="Clicked!")
file_menu = Menu(menu_bar, tearoff=False)
file_menu.add_command(label="An example item", command=lambda: clicked(file_menu))
menu_bar.add_cascade(label="File", menu=file_menu)
root.config(menu=menu_bar)
root.mainloop()
I do not know if that used to be different on 2.7, but it does not work on 3.4 anymore.
On python 3.4 you should start counting entries with 0 and use entryconfig.
menu.entryconfig(0, label = "Clicked!")
http://effbot.org/tkinterbook/menu.htm
Check this dynamic menu example. The main feature here is that you don't need to care about a serial number (index) of your menu item. No index (place) of your menu is needed to track. Menu item could be the first or the last, it doesn't matter. So you could add new menus without index tracking (position) of your menus.
The code is on Python 3.6.
# Using lambda keyword and refresh function to create a dynamic menu.
import tkinter as tk
def show(x):
""" Show your choice """
global label
new_label = 'Choice is: ' + x
menubar.entryconfigure(label, label=new_label) # change menu text
label = new_label # update menu label to find it next time
choice.set(x)
def refresh():
""" Refresh menu contents """
global label, l
if l[0] == 'one':
l = ['four', 'five', 'six', 'seven']
else:
l = ['one', 'two', 'three']
choice.set('')
menu.delete(0, 'end') # delete previous contents of the menu
menubar.entryconfigure(label, label=const_str) # change menu text
label = const_str # update menu label to find it next time
for i in l:
menu.add_command(label=i, command=lambda x=i: show(x))
root = tk.Tk()
# Set some variables
choice = tk.StringVar()
const_str = 'Choice'
label = const_str
l = ['dummy']
# Create some widgets
menubar = tk.Menu(root)
root.configure(menu=menubar)
menu = tk.Menu(menubar, tearoff=False)
menubar.add_cascade(label=label, menu=menu)
b = tk.Button(root, text='Refresh menu', command=refresh)
b.pack()
b.invoke()
tk.Label(root, textvariable=choice).pack()
root.mainloop()
Related
I created a menu item and want to run a function within that menu which will run a simple calculation based on a entry. When I run the code in my terminal, I can see my window and the menu item with the entry widget. But, I don't see anything and result from my function. I don't get an error from the terminal. Below is my code. Where did I mess in my code?
from tkinter import *
root = Tk()
root.title(" My calculator")
root.geometry("400x400")
# Defining calculator 1 function
def calculator_1():
# creating an entry
frame1.pack(fill="both",expand=1)
e1 =Entry(frame1)
e1.pack(pady=5)
# Defining the formula function
def formula():
res = (int(e1.get()) + 1)
myText.set(res)
# creating a calculate button
my_button = Button(frame1, text="Click to calculate", command=formula)
my_button.pack(pady=5)
myText=StringVar()
result=Label(frame1, text=" your results is ", textvariable =myText)
result.pack(pady=5)
label_result =Label(frame1, text= "Your result is")
label_result.pack(pady=5)
# Define Main menu
my_menu = Menu(root)
root.config(menu=my_menu)
#create menu items
math_menu = Menu(my_menu)
my_menu.add_cascade(label="MathCards",menu=math_menu)
math_menu.add_command(label="Calculator 1",command=calculator_1)
math_menu.add_separator()
math_menu.add_command(label="Exit", command=root.quit)
# Creating a frame
frame1 = Frame(root, width =400, height=400)
root.mainloop()
I have a button called view and when it is clicked on it will create a new window with a list in a listbox and a list of checkboxes that correspond to the listbox. When switching through the items in the listbox you will see that the listbox items are independent of each other and will have their own check box values. As of right now it will remember the checkbox values for each listbox item except when you close the created window. When you close the second window that was created all of that information disappears when you try and open the window back up again. I need a way to create a second window, do everything it does now with the listbox and checkboxes, but when closed it can be opened again and pick up where you left off.
For example, if I highlight the first item in the listbox and check the first checkbox, I should be able to close that window and open it again and when the first item in the listbox is highlighted, I see that there is a check in the first checkbox.
import tkinter
from tkinter import *
def myfunction(event):
canvas1.configure(scrollregion=canvas1.bbox("all"))
def onselect(evt):
# Note here that Tkinter passes an event object to onselect()
w = evt.widget
x = 0
index = int(w.curselection()[0])
value = w.get(index)
print('You selected item %d: "%s"' % (index, value))
for y in enable:
for item in list_for_listbox:
checkbuttons[item][y][1].grid_forget()
checkbuttons[value][y][1].grid(row=x, column=0)
# Label(frame2, text="some text").grid(row=x, column=1)
x += 1
def printcommand():
for item in list_for_listbox:
for y in enable:
print(item + " [" + y + "] " + str(checkbuttons[item][y][0].get()))
def create_new_window():
global new_window
new_window = tkinter.Toplevel()
new_window.geometry("750x500")
new_window_commands()
master = tkinter.Tk()
master.title("Checkboxes test")
master.geometry("750x500")
button1 = Button(master, command =create_new_window,text="View")
button1.place(x=50,y=250)
def new_window_commands():
# enable = ['button 1', 'button 2', 'button 3', 'button 4', 'button 5', 'button 6', 'button 7']
global list_for_listbox
global enable
global checkbuttons
global canvas1
enable = []
for x_number_of_items in range(1, 15):
enable.append("button " + str(x_number_of_items))
list_for_listbox = ["one", "two", "three", "four"]
listbox = Listbox(new_window)
listbox.place(x=5, y=5, width=100, height=10 + 16*len(list_for_listbox))
listbox.update()
frame1 = Frame(new_window, borderwidth=1, relief=GROOVE, highlightthickness=1, highlightbackground="black",
highlightcolor="black")
frame1.place(x=listbox.winfo_width() + 10, y=5, width=300, height=listbox.winfo_height())
canvas1 = Canvas(frame1)
frame2 = Frame(canvas1, height=500)
scrollbar1 = Scrollbar(frame1, orient="vertical", command=canvas1.yview)
canvas1.configure(yscrollcomman=scrollbar1.set)
scrollbar1.pack(side="right", fill="y")
canvas1.pack(side="left")
canvas1.create_window((0, 0), window=frame2, anchor='nw')
frame2.bind("<Configure>", myfunction)
printbutton = Button(new_window, text="Print", command=printcommand)
printbutton.place(x=100, y=250)
checkbuttons = {}
for item in list_for_listbox:
listbox.insert(END, item)
checkbuttons[item] = (dict())
for y in enable:
temp_var = BooleanVar()
checkbuttons[item][y] = [temp_var, Checkbutton(frame2, text=y, variable=temp_var)]
listbox.bind('<<ListboxSelect>>', onselect)
print(enable)
mainloop()
printcommand()
With your current structure, the simplest fix would be:
Only create the new_window once.
withdraw() new_window instead of letting it close each time.
Open the same instance of new_window again when called upon.
You'll need to implement the following:
# Default your new_window to None
new_window = None
def create_new_window():
global new_window
# If new_window doesn't exist, create a new one
if not new_window:
new_window = tkinter.Toplevel()
new_window.geometry("750x500")
# add a new protocol to redirect on closing the window.
new_window.protocol("WM_DELETE_WINDOW", hide_window)
new_window_commands()
else:
# if new_window already exist, just unhide it
new_window.deiconify()
# add a new function for when window is closing
def hide_window():
global new_window
new_window.withdraw()
You might also want to add the same protocol method under master so that when it closes, destroy both master and new_window object:
master.protocol('WM_DELETE_WINDOW', destroy_all)
def destroy_all():
global master
global new_window
master.destroy()
new_window.destroy()
If possible, for your next tkinter code I would suggest considering an object oriented approach though. I will see if I can provide a short sample here later.
As a side note, while I understand a lot of documentations in tkinter uses the from tkinter import * approach, I would discourage this practice and advise to import tkinter as tk instead (or as you already did, import tkinter, which accomplishes the same thing). See relevant answer here
Here's a quick sample of OOP approach in a similar vein:
import tkinter as tk
# Here the main window can be called upon as its own instance with its own instance attributes.
class Window(tk.Tk):
def __init__(self):
super().__init__()
self.main_button = tk.Button(self, text="Creat a sub window", command=self.open_sub_window)
self.main_button.pack()
# define the things you wish to retain under the main window as an instance attribute
self.sub_check_var = tk.BooleanVar()
self.sub_entry_var = tk.StringVar()
# when creating a new window, just reference back to the main attributes you've already created.
def open_sub_window(self):
self.sub_window = tk.Toplevel()
tk.Checkbutton(self.sub_window, text="I'm a checkbox!", variable=self.sub_check_var).pack()
lbl_frm = tk.LabelFrame(self.sub_window, text="I am an entry!")
lbl_frm.pack()
tk.Entry(lbl_frm, text=self.sub_entry_var).pack()
gui = Window()
gui.mainloop()
Note this is but one way to do it. You just need to feel around to get comfortable with your implementation, there's no right/wrong way to do things.
I am creating a GUI that builds information about a person. I want the user to select their birth month using a drop down bar, with the months configured earlier as a list format.
from tkinter import *
birth_month = [
'Jan',
'Feb',
'March',
'April'
] #etc
def click():
entered_text = entry.get()
Data = Tk()
Data.title('Data') #Title
label = Label(Data, text='Birth month select:')
label.grid(row=2, column=0, sticky=W) #Select title
How can I create a drop down list to display the months?
To create a "drop down menu" you can use OptionMenu in tkinter
Example of a basic OptionMenu:
from Tkinter import *
master = Tk()
variable = StringVar(master)
variable.set("one") # default value
w = OptionMenu(master, variable, "one", "two", "three")
w.pack()
mainloop()
More information (including the script above) can be found here.
Creating an OptionMenu of the months from a list would be as simple as:
from tkinter import *
OPTIONS = [
"Jan",
"Feb",
"Mar"
] #etc
master = Tk()
variable = StringVar(master)
variable.set(OPTIONS[0]) # default value
w = OptionMenu(master, variable, *OPTIONS)
w.pack()
mainloop()
In order to retrieve the value the user has selected you can simply use a .get() on the variable that we assigned to the widget, in the below case this is variable:
from tkinter import *
OPTIONS = [
"Jan",
"Feb",
"Mar"
] #etc
master = Tk()
variable = StringVar(master)
variable.set(OPTIONS[0]) # default value
w = OptionMenu(master, variable, *OPTIONS)
w.pack()
def ok():
print ("value is:" + variable.get())
button = Button(master, text="OK", command=ok)
button.pack()
mainloop()
I would highly recommend reading through this site for further basic tkinter information as the above examples are modified from that site.
Here Is my function which will let you create a Combo Box with values of files stored in a Directory and Prints the Selected Option value in a Button Click.
from tkinter import*
import os, fnmatch
def submitForm():
strFile = optVariable.get()
# Print the selected value from Option (Combo Box)
if (strFile !=''):
print('Selected Value is : ' + strFile)
root = Tk()
root.geometry('500x500')
root.title("Demo Form ")
label_2 = Label(root, text="Choose Files ",width=20,font=("bold", 10))
label_2.place(x=68,y=250)
flist = fnmatch.filter(os.listdir('.'), '*.mp4')
optVariable = StringVar(root)
optVariable.set(" Select ") # default value
optFiles = OptionMenu(root, optVariable,*flist)
optFiles.pack()
optFiles.place(x=240,y=250)
Button(root, text='Submit', command=submitForm, width=20,bg='brown',fg='white').place(x=180,y=380)
root.mainloop()
I am creating a simple temperature converter in python using tkinter. I have created a drop down menu with the options and a convert button. What I want to do is when the dropdown menu's changes I want the button to do a different thing. How can I achieve this ?
(example in this case: if celcius to fahrenheit is chosen button should convert cel to fahrenheit if fahr to celsius is chosen it should convert that way. )
Here is the code:
from tkinter import *
def converter():
# Create functions for conversion
def cel_fahr():
res = int(entry.get()) * 9/5 +32
print (res)
def fahr_cel():
res = (int(entry.get()) - 32) * 5/9
print (res)
#Options list for the dropdown
list_opt = ['Celsius to Fahrenheit', 'Fahrenheit to Celsius']
# Create the main window
root = Tk()
# Rename the title of the window
root.title("Temperature Converter")
# Set the size of the window
root.geometry("250x250")
# Set resizable FALSE
root.resizable(0,0)
# Create a variable for the default dropdown option
var1 = StringVar()
# Set the default drop down option
var1.set(list_opt[0])
# Create the dropdown menu
dropdown = OptionMenu(root, var1, *list_opt)
dropdown.configure(state="active")
# Place the dropdown menu
dropdown.place(x=45, y=10)
# Create an entry
entry = Entry(root)
entry.place (x=47, y=60)
#Create a button
button = Button(root, text='Convert', command=cel_fahr)
button.place(x=85,y=90)
#I TRIED THIS BUT NO
#if var1 == list_opt[0]:
#button = Button(root, text='Convert', command=cel_fahr)
#button.place(x=85,y=90)
#if var1 == list_opt[1]:
#button = Button(root, text='Convert', command=fahr_cel)
#button.place(x=85,y=90)
root.mainloop()
converter()
Switched up your code a little bit:
from tkinter import *
def converter():
# Create functions for conversion
def cel_fahr():
res = int(entry.get()) * 9/5 +32
print (res)
def fahr_cel():
res = (int(entry.get()) - 32) * 5/9
print (res)
def convert():
if selected.get() == 'Celsius to Fahrenheit':
cel_fahr()
else:
fahr_cel()
#Options list for the dropdown
list_opt = ['Celsius to Fahrenheit', 'Fahrenheit to Celsius']
# Create the main window
root = Tk()
# Rename the title of the window
root.title("Temperature Converter")
# Set the size of the window
root.geometry("250x250")
# Set resizable FALSE
root.resizable(0,0)
# Create a variable for the default dropdown option
selected = StringVar(root)
# Set the default drop down option
selected.set('Celsius to Fahrenheit')
# Create the dropdown menu
dropdown = OptionMenu(root, selected, 'Celsius to Fahrenheit', 'Fahrenheit to Celsius')
# Place the dropdown menu
dropdown.place(x=45, y=10)
# Create an entry
entry = Entry(root)
entry.place (x=47, y=60)
#Create a button
button = Button(root, text='Convert', command=convert)
button.place(x=85,y=90)
root.mainloop()
converter()
Instead of the options being in a list, I've just dropped them into the menu when it's created. When the button is pressed, it then calls a function which decides which conversion to use, based on the value selected in the dropdown menu.
I've also changed the variable name for var1 (to "selected"), because it's not very descriptive, and got a bit confusing to code with.
I've been trying to bind a callback to a menu item selection, instead of using the command= functionality of the add_command method.
However, it seems that no matter what I try it will only give me a proper index of the menu item ("Menu 1" and "Menu 2") when they are select, instead of the index of the buttons of the menu. When the button is pressed in will just print None.
This is my current test code, but I've been trying a bunch of different stuff.
import tkinter as tk
def menucallback(event):
print(root.call(event.widget, "index", "active"))
root = tk.Tk()
# create menu
menubar = tk.Menu(root)
menu1 = tk.Menu(menubar, tearoff=0)
menu1.add_command(label="Button 1")
menu1.add_command(label="Button 2")
menubar.add_cascade(label="Menu 1", menu=menu1)
menu2 = tk.Menu(menubar, tearoff=0)
menu2.add_command(label="Button 6")
menu2.add_command(label="Button 7")
menubar.add_cascade(label="Menu 2", menu=menu2)
tk.Tk.config(root, menu=menubar)
# bind to function
menubar.bind("<<MenuSelect>>", menucallback)
root.mainloop()
In case it matters, I'm on Windows 7 with Python 3.4
If you want the event to trigger on the dropdown menus, you need to add the same binding to each menu.
The reason you get none when selecting the menu item is likely because the state of the menu changes before the callback is called (ie: there is no active item after you click).
It is maybe a little bit late for you, but I was on a point I thought I would need it.
In fact I do not, but maybe someone else needs it:
import tkinter as tk
def menucallback(event):
check = root.call(event.widget, "index","active")
if check != "none":
menu_index.set(check)
def foo():
display.configure(text=menu_index.get())
index = menu_index.get()
if index == 0:
display.configure(bg='blue')
if index == 1:
display.configure(bg='red')
display.wait_variable(menu_index)
foo()
root = tk.Tk()
display = tk.Label(root, text='default')
display.pack(fill='x')
menu_index = tk.IntVar()
menubar =tk.Menu(root)
menu1 = tk.Menu(menubar, tearoff=0)
menu1.add_command(label="Button1")
menu1.add_command(label="Button2")
menubar.add_cascade(label='Menu1', menu=menu1)
menu1.bind('<<MenuSelect>>', menucallback)
tk.Tk.config(root, menu=menubar)
foo()
root.mainloop()
Finally found a usefull place for that code. It can be used to create scrolling buttons on the menu.
Note
This code seems to be Windows only solution.