[Tutor] events and popup menus

Peter Otten __peter__ at web.de
Thu May 3 12:30:13 CEST 2012

Chris Hare wrote:

> I have four images in a frame.  I want to pop up a menu when the user
> right clicks on an image, and when they choose an option from the menu,
> execute the action.
> I can create the popup menu, and bind it to the image.  However, what I
> can't figure out is how to detect in the popup menu code which image fired
> the event so I can do the right thing (like display a larger version of
> the image, etc.)
> # create a menu
> self.popup = Menu(self.pictureWindow, tearoff=0)
>  self.popup.add_command(label="Change Picture",
>  command=self.selectPicture) self.popup.add_command(label="Make Primary",
>  command=self.selectPicture) self.popup.add_command(label="Large View",
>  command=self.selectPicture)

You should have a different callback for every menu item:

self.popup.add_command(label="Change Picture", command=self.change_picture)
self.popup.add_command(label="Large View", command=self.large_view)

> self.picture1.bind("<Button-1>", self.do_popup)
>  def do_popup(self,event):
>             # display the popup menu
>           try:
>            self.popup.tk_popup(event.x_root, event.y_root, 0)
>                  finally:
>                          # make sure to release the grab (Tk 8.0a1 only)
>                          self.popup.grab_release()
> Thanks for the advice!

You can remember the widget from do_popup()'s event argument

def do_popup(self, event):
    self.current_picture = event.widget

and later refer to it in the menu callbacks 

def select_picture(self):
    picture = self.current_picture

I got a bit distracted struggling with PIL, therefore my "self-contained 
demo" got rather baroque. You may still find it useful:

$ cat tk_popup_demo.py
import sys
import Tkinter as tk
import ImageTk
import Image

current_label = None

def do_popup(event):
    global current_label
    current_label = event.widget
        popup.tk_popup(event.x_root, event.y_root, 0)

def rotate_picture():
    image = current_label.photoimage.image.rotate(90)
    photoimage = ImageTk.PhotoImage(image)
    photoimage.image = image
    current_label.photoimage = current_label["image"] = photoimage

def flip_picture():
    print "flip picture"

def load_image(filename, maxsize=(500, 500), padcolor="#f80"):
    image = Image.open(filename)
    if image.size != maxsize:
        padded_image = Image.new(image.mode, maxsize, color=padcolor)
        maxx, maxy = maxsize
        x, y = image.size
        padded_image.paste(image, ((maxx-x)//2, (maxy-y)//2))
        image = padded_image
    assert image.size == maxsize
    return image

root = tk.Tk()

picturefiles = sys.argv[1:4]
for i, filename in enumerate(picturefiles):
    image = load_image(filename)
    photoimage = ImageTk.PhotoImage(image)
    photoimage.image = image

    label = tk.Label(root, image=photoimage)
    label.photoimage = photoimage
    label.grid(row=0, column=i)
    label.bind("<Button-3>", do_popup)

popup = tk.Menu(root, tearoff=0)
popup.add_command(label="Rotate", command=rotate_picture)
popup.add_command(label="Flip", command=flip_picture)


Invoke with a few picture names (all but the first three will be ignored):

$ python tk_popup_demo.py *.jpg

More information about the Tutor mailing list