[Tkinter-discuss] FocusOut on a popup widget

Vasilis Vlachoudis Vasilis.Vlachoudis at cern.ch
Tue Apr 15 14:30:43 CEST 2008


Dear all,

in my application I have developed a small widget class "InPlaceEdit" to 
allow the user to edit in place the content of an item from a listbox. 
The class is creating a temporary popup Entry() (or overridden with any 
other widget) and placing it exactly on the coordinates of the listbox 
item to edit.

Now my problem is the following. I am binding the <FocusOut> so when the 
user clicks outside the widget, to destroy the widget and replace the 
value in the listbox. But, if the user clicks on a button, then the 
program first executes the command of the button and then it sends the 
<FocusOut> event to the InPlaceEdit, with an end result that the content 
is updated after the command is executed. The same happens also with 
Menu entries.

What should I bind to get a notification that I will lose the focus (or 
something similar) before executing the command of the button?

Vasilis


#===============================================================================
# Class to edit in place the contents of a listbox
#===============================================================================
class InPlaceEdit:
    def __init__(self, listbox, item=ACTIVE, value=None):
        # Return value
        self.value = None    # Result
        self.item  = item

        # Find active
        try: self.active = listbox.index(self.item)
        except: return

        self.listbox = listbox

        # Create and set value
        self.frame = Frame(listbox, relief=None)
        self.createWidget()
        self.set(value)
        self.defaultBinds()

        # Bindings
        self.frame.bind("<FocusOut>", self.focusOut)
        self.frame.bind("<Unmap>", self.cancel)
        self.listbox.bind("<Configure>", self.resize)

        # Show and wait to be destroyed
        self.resize()
        self.frame.wait_window()

    # ----------------------------------------------------------------------
    # Override method if another widget is requested
    # ----------------------------------------------------------------------
    def createWidget(self):
        self.edit = Entry(self.frame, background="White")
        self.edit.pack(expand=YES, fill=BOTH)
        self.edit.focus_set()

    # ----------------------------------------------------------------------
    # Set default bindings
    # ----------------------------------------------------------------------
    def defaultBinds(self):
        try:
            self.edit.bind("<Return>", self.ok)
            self.edit.bind("<Escape>", self.cancel)
        except AttributeError:
            pass

    # ----------------------------------------------------------------------
    def resize(self, event=None):
        x, y, w, h = self.listbox.bbox(self.item)
        w = self.listbox.winfo_width()
        h += 2
        try:
            self.frame.place(in_=self.listbox,
                    x=x-1, y=y-1,
                    width=w, height=h,
                    bordermode=OUTSIDE)
            self.frame.update_idletasks()
        except TclError:
            pass

    # ----------------------------------------------------------------------
    # Override method to set the value
    # ----------------------------------------------------------------------
    def set(self, value):
        if value is None:
            value = self.listbox.get(self.item)
        self.edit.delete(0, END)
        self.edit.insert(0, value)
        self.edit.selection_range(0, END)

    # ----------------------------------------------------------------------
    # Override method to get the value
    # ----------------------------------------------------------------------
    def get(self):
        return self.edit.get()

    # ----------------------------------------------------------------------
    def ok(self, event=None):
        self.value = self.get()
        self.frame.unbind('<FocusOut>')
        self.frame.place_forget()
        self.frame.destroy()
        self.listbox.focus_set()
        act = self.listbox.index(ACTIVE)
        sel = self.listbox.selection_includes(self.active)
        self.listbox.delete(self.active)
        self.listbox.insert(self.active, self.value)
        if sel:
            self.listbox.selection_set(self.active)
        self.listbox.activate(act)
        return "break"

    # ----------------------------------------------------------------------
    def focusOut(self, event=None):
        self.ok()

    # ----------------------------------------------------------------------
    def cancel(self, event=None):
        self.frame.place_forget()
        self.frame.destroy()
        self.listbox.focus_set()
        return "break"

-------------- next part --------------
A non-text attachment was scrubbed...
Name: Vasilis_Vlachoudis.vcf
Type: text/x-vcard
Size: 312 bytes
Desc: Vasilis_Vlachoudis.vcf
Url : http://mail.python.org/pipermail/tkinter-discuss/attachments/20080415/3edaa4bf/attachment.vcf 


More information about the Tkinter-discuss mailing list