14

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()
kiri
  • 2,522
  • 4
  • 26
  • 44

3 Answers3

13

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()
kiri
  • 2,522
  • 4
  • 26
  • 44
7

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

mvbentes
  • 1,022
  • 12
  • 24
  • Thank you, even 5 years later your answer is really helpful and maked my project even better. But in `menu.entryconfig(0, label = "Clicked!")`, the `menu` must the menu where the entry we want to config. I mean if the menu item we want to edit is in the `file_menu`, we must make it `file_menu.entryconfig(0, label = "Clicked!")`. – Yılmaz Alpaslan May 04 '21 at 10:09
  • 1
    I worked out why the index changes and it isn't from the python version - when the menu is set with `tearoff=False` the item index starts at `0`, while when `tearoff=True` items start at `1` so that means the tearoff menu item is at `0` making our first item at `1`. Also if your index is greater than the number of items, you always get the last item. – sambler Dec 19 '22 at 10:51
1

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()
FooBar167
  • 2,721
  • 1
  • 26
  • 37