Teek
latest
  • Beginner-friendly tutorial (start here)
  • Porting from Tkinter
  • Concurrency
  • Geometry Managers: pack, grid, place
  • Widget Reference
    • Canvas Widget
    • Menu Widget
      • Creating Menu Items
      • Reference
    • Notebook Widget
    • Text Widget
  • Binding
  • Dialogs
  • Miscellaneous Classes
  • Platform Information
  • Extras
  • Event Loop
  • Tcl Calls
Teek
  • Docs »
  • Widget Reference »
  • Menu Widget
  • Edit on GitHub

Menu Widget¶

Manual page: menu(3tk)

You can use menu widges for a few different things:

  • Menu bars are menus that are typically displayed at the top of a window, or top of the screen if you are using e.g. Mac OSX.
  • Pop-up menus open when the user e.g. right-clicks something.

Here is an example of a menu bar:

import teek

window = teek.Window()

def hello():
    print("hello")

window.config['menu'] = teek.Menu([
    teek.MenuItem("File", [
        teek.MenuItem("New", hello),
        teek.MenuItem("Open", hello),
        teek.MenuItem("Save", hello),
        teek.MenuItem("Quit", hello),
    ]),
    teek.MenuItem("Edit", [
        teek.MenuItem("Cut", hello),
        teek.MenuItem("Copy", hello),
        teek.MenuItem("Paste", hello),
    ]),
])

window.geometry(300, 200)
window.on_delete_window.connect(teek.quit)
teek.run()

As you can see, Menu takes one argument, which is a list of MenuItem objects. This example uses two kinds of menu items; some menu items just call the hello() function when they are clicked, while the “File” and “Edit” items display submenus. There are more details about different kinds of items below.

Here is a pop-up menu example. See bind documentation for more details about the binding stuff.

import teek

window = teek.Window()

def hello():
    print("hello")

menu = teek.Menu([
    teek.MenuItem("Cut", hello),
    teek.MenuItem("Copy", hello),
    teek.MenuItem("Paste", hello),
])

def on_right_click(event):
    menu.popup(event.rootx, event.rooty)

if teek.windowingsystem() == 'aqua':
    # running on Mac OSX, there's no right-click so this must be done a bit
    # differently
    window.bind('<Button-2>', on_right_click, event=True)
    window.bind('<Control-Button-1>', on_right_click, event=True)
else:
    window.bind('<Button-3>', on_right_click, event=True)

window.geometry(300, 200)
window.on_delete_window.connect(teek.quit)
teek.run()

I found the Mac OSX specific code from here.

Menu widgets are not Ttk widgets. If you don’t know what that means, you should go here and learn. The only practical thing I can think of right now is that menus don’t have a state attribute.

Creating Menu Items¶

There are a few different ways to create instances of MenuItem. Here label must be a string.

  • MenuItem() creates a separator.
  • MenuItem(label, function) creates a command item that runs function() when it’s clicked. See also Button.
  • MenuItem(label, checked_var) creates a checkbutton menu item. The checked_var must be a BooleanVar. See also Checkbutton.
  • MenuItem(label, string_var, value) creates a radiobutton menu item. Use this for letting the user choose one of multiple options. Clicking the item sets value to string_var. The string_var must be a StringVar object, and value must be a string.
  • MenuItem(label, menu) creates a cascade menu item; that is, it displays a submenu with the items of menu in it. The menu must be a Menu widget.
  • MenuItem(label, item_list) is a handy way to create a new Menu and add it as a cascade item as explained above.

You can also pass options as keyword arguments in any of the above forms. The available options are documented as MENU ENTRY OPTIONS in menu(3tk). For example, instead of this…

MenuItem("Copy", do_the_copy)

…you probably want to do something like this:

MenuItem("Copy", do_the_copy, accelerator='Ctrl+C')

Note that this does not bind anything automatically, so you need to do that yourself if want that Ctrl+C actually does something.

Here is an example that demonstrates most things. See StringVar and BooleanVar documentation for more info about them.

import teek


def on_click():
    print("clicked")

def on_check(is_checked):
    print("is it checked now?", is_checked)

def on_choice(choice):
    print("chose", repr(choice))


window = teek.Window()

submenu = teek.Menu([
    teek.MenuItem("Asd", on_click),
    teek.MenuItem("Toot", on_click),
])

check_var = teek.BooleanVar()
check_var.write_trace.connect(on_check)
choice_var = teek.StringVar()
choice_var.write_trace.connect(on_choice)

window.config['menu'] = teek.Menu([
    teek.MenuItem("Stuff", [
        teek.MenuItem("Click me", on_click),
        teek.MenuItem("Check me", check_var),
        teek.MenuItem("More stuff", submenu),
        teek.MenuItem(),      # separator
        teek.MenuItem("Choice 1", choice_var, "one"),
        teek.MenuItem("Choice 2", choice_var, "two"),
        teek.MenuItem("Choice 3", choice_var, "three"),
    ]),
])

window.geometry(300, 200)
window.on_delete_window.connect(teek.quit)
teek.run()

Reference¶

class teek.Menu(items=(), **kwargs)[source]¶

This is the menu widget.

The items should be an iterable of MenuItem objects, and it’s treated so that this…

menu = teek.Menu([
    teek.MenuItem("Click me", print),
    teek.MenuItem("No, click me instead", print),
])

…does the same thing as this:

menu = teek.Menu()
menu.append(teek.MenuItem("Click me", print))
menu.append(teek.MenuItem("No, click me instead", print))

Menu widgets behave like lists of menu items, so if you can do something to a list of MenuItem objects, you can probably do it directly to a Menu widget as well.

However, menu widgets don’t support slicing, like lists do:

>>> menu = teek.Menu([
...     teek.MenuItem("Click me", print),
... ])
>>> menu.append(teek.MenuItem("No, click me instead", print))
>>> menu
<teek.Menu widget: contains 2 items>
>>> menu[0]     # this works
<MenuItem('Click me', <built-in function print>): type='command', added to a menu>
>>> for item in menu:   # this works
...     print(item)
...
<MenuItem('Click me', <built-in function print>): type='command', added to a menu>
<MenuItem('No, click me instead', <built-in function print>): type='command', added to a menu>
>>> menu[:2]    # but this doesn't work
Traceback (most recent call last):
  ...
TypeError: slicing a Menu widget is not supported
>>> list(menu)[:2]    # workaround      # doctest: +ELLIPSIS
[<MenuItem(...): ...>, <MenuItem(...): ...>]

Menu objects assume that nothing changes the underlying Tk menu widget without the Menu object. For example:

>>> menu = teek.Menu()
>>> command = menu.to_tcl()
>>> command      # doctest: +SKIP
'.menu1'
>>> # DON'T DO THIS, this is a bad idea
>>> teek.tcl_eval(None, '%s add checkbutton -command {puts hello}' % command)
>>> len(menu)   # the menu widget doesn't know that we added an item
0

If you don’t know what tcl_eval() does, you don’t need to worry about doing this accidentally.

Manual page: menu(3tk)

popup(x, y, menu_item=None)[source]¶

Displays the menu on the screen.

x and y are coordinates in pixels, relative to the screen. See tk_popup(3tk) for details. If menu_item is given, its index is passed to tk_popup(3tk).

There are two ways to show popup menus in Tk. This is one of them, and post is another. I spent a while trying to find something that explains the difference, and the best thing I found is this book. The book uses tk_popup, and one of the authors is John Ousterhout, the creator of Tcl and Tk.

class teek.MenuItem(*args, **kwargs)[source]¶

Represents an item of a menu. See Creating Menu Items for details about the arguments.

Tk’s manual pages call these things “menu entries” instead of “menu items”, but I called them items to avoid confusing these with Entry.

There are two kinds of MenuItem objects:

  • Menu items that are not in any Menu widget because they haven’t been added to a menu yet, or they have been removed from a menu. Trying to do something with these menu items will likely raise a RuntimeError.
  • Menu items that are currently in a Menu.

Here’s an example:

>>> item = teek.MenuItem("Click me", print)
>>> item.config['label'] = "New text"
Traceback (most recent call last):
    ...
RuntimeError: the MenuItem hasn't been added to a Menu yet
>>> menu = teek.Menu()
>>> menu.append(item)
>>> item.config['label'] = "New text"
>>> item.config['label']
'New text'
config¶

This attribute is similar to Widget.config. See MENU ENTRY OPTIONS in menu(3tk).

The types of the values are the same as for similar widgets. For example, the 'command' of a Button widget is a Callback object connected to a function passed to Button, and so is the 'command' of teek.MenuItem("Click me", some_function).

type¶

This is a string. Currently the possible values are 'separator', 'checkbutton', 'command', 'cascade' and 'radiobutton' as documented above. Don’t set this attribute yourself.

Next Previous

© Copyright 2018, Akuli Revision c360fbfe.

Built with Sphinx using a theme provided by Read the Docs.