Question: How to Prevent Tkinter Menu from Taking Keyboard Focus

galyle galyle at gmail.com
Tue Oct 4 14:35:25 EDT 2011


On Oct 4, 11:05 am, galyle <gal... at gmail.com> wrote:
> On Oct 4, 9:45 am, woooee <woo... at gmail.com> wrote:
>
>
>
>
>
>
>
>
>
> > Sorry, I did not understand the question correctly, and so have added
> > another focus_set for the entry after the menu's creation.  You can
> > still enter after the menu comes up, even though you can't see where
> > you are entering.
>
> > import Tkinter
>
> > class demo:
> >     def __init__(self, parent):
> >         self._entry = Tkinter.Entry(width = 60)
> >         self._suggestions = Tkinter.Menu(parent, tearoff = 0,
> > takefocus = 0)
> >         self._entry.pack(padx = 20, pady = 20)
> >         self._entry.bind('<Key>', self._suggest_text, add = '+')
> >         self._entry.focus_set()
>
> >     def _suggest_text(self, event):
> >         curr = self._entry.get() + repr(event.char)[1]
> >         x = self._entry.winfo_rootx()
> >         y = self._entry.winfo_rooty()
> >         y += self._entry.winfo_height()
> >         try:
> >             self._suggestions.delete(0, 'end')
> >             self._suggestions.add_command(label = curr + '_1')
> >             self._suggestions.add_command(label = curr + '_2')
> >             self._suggestions.add_command(label = curr + '_3')
> >             self._suggestions.add_command(label = curr + '_4')
> >             self._suggestions.post(x, y)
> >         finally:
> >             self._suggestions.grab_release()
>
> >         self._entry.focus_set()
>
> > if __name__ == '__main__':
> >     root = Tkinter.Tk()
> >     root.title('A Problem')
> >     demo(root)
> >     root.mainloop()
>
> Perhaps it is because I'm trying this on Windows, but the above code
> does not work for me.  After the menu is posted, no further keyboard
> input gets directed to the entry until the menu is unposted.
>
> It looks like my best bet is to use the ComboBox suggested above.  The
> ComboBox method is very close to working, but I've got a problem now
> where all focus on the app is directed to the ComboBox entry (I need
> to set it that way to redirect keyboard input from the popup menu),
> making it impossible to close the app without killing it.  I've tried
> to return focus to the entry parent by binding the entry to <FocusOut>
> and <Leave>, but this has the effect of making the popup take the
> focus after every keystroke, which is not what I want.
>
> The (almost working) demo below should demonstrate the issue fairly
> well:
>
> import Tkinter
> import Pmw
>
> class demo:
>     def __init__(self, parent):
>         self._search_bar = Pmw.ComboBox(parent,
>             label_text = 'Register Mnemonic',
>             labelpos = 'w', entry_width = 60)
>         self._search_bar.pack(padx = 20, pady = 20)
>         self._search_bar._entryfield.component('entry').bind('<Key>',
>             self._suggest_text, add = '+')
>
>     def _suggest_text(self, event):
>         curr = self._search_bar._entryfield.getvalue()
>         curr += repr(event.char)[1]
>         self._search_bar._list.setlist([curr + '_0', curr + '_1',
>             curr + '_2'])
>         self._search_bar._postList(event)
>         self._search_bar._entryfield.component('entry').focus_set()
>         self._search_bar._popup.lift()
>
> if __name__ == '__main__':
>     root = Tkinter.Tk()
>     root.title('A Problem')
>     demo(root)
>     root.mainloop()

Well, it required quite a bit of digging, but I finally have what I
want.  For those who are curious, the following demo should provide
some help:


import Tkinter
import Pmw

class demo:
    def __init__(self, parent):
        self._parent = parent
        self._search_bar = Pmw.ComboBox(parent,
            label_text = 'Register Mnemonic',
            labelpos = 'w', entry_width = 60)
        self._search_bar.pack(padx = 20, pady = 20)
        self._search_bar._entryfield.component('entry').bind('<Key>',
            self._suggest_text, add = '+')
 
self._search_bar._entryfield.component('entry').bind('<Escape>',
            self._remove_list, add = '+')
 
self._search_bar._entryfield.component('entry').bind('<space>',
            self._remove_list, add = '+')
 
self._search_bar._entryfield.component('entry').bind('<Return>',
            self._remove_list, add = '+')
        self._search_bar._popup.bind('<ButtonRelease-1>',
            self._remove_list, add = '+')

    def _suggest_text(self, event):
        x = self._search_bar._entryfield.winfo_rootx()
        y = self._search_bar._entryfield.winfo_rooty() + \
            self._search_bar._entryfield.winfo_height()
        w = self._search_bar._entryfield.winfo_width() + \
            self._search_bar._arrowBtn.winfo_width()

        curr = self._search_bar._entryfield.getvalue()
        curr += repr(event.char)[1]
        self._search_bar._list.setlist([curr + '_0', curr + '_1',
            curr + '_2'])

        self._search_bar._list.configure(hull_width=w)
        Pmw.setgeometryanddeiconify(self._search_bar._popup,
            '+%d+%d' % (x, y))

        self._search_bar._popup.lift()

    def _remove_list(self, event):
        self._search_bar._popup.withdraw()

if __name__ == '__main__':
    root = Tkinter.Tk()
    root.title('A Problem')
    demo(root)
    root.mainloop()



More information about the Python-list mailing list