3

Is it possible to make Combobox editable while dropdown is opened? I haven't found any solution. I want to make it more like Google Search but using ComboBox.

stovfl
  • 14,998
  • 7
  • 24
  • 51
KK.
  • 33
  • 1
  • 5
  • Thanks @stovfl: But I'm not searching for auto completion. I just want to type anything in combobox while dropdown is opened. Rightnow as long as dropdown is open, we are not able to write anything. My question is, can we able to make combobox editable while dropdown opended? means dropdown will open when we type anything in the combobox and we are still able to type even after dropdown is opened. – KK. Jan 17 '20 at 09:14
  • ***"type in `Entry` while `Listbox` is opened"***: That's out of scope for `Combobox`. You can show the `Listbox` by send `.event_generate('')` but then the `Entry` loose the `Focus`. If you `Focus` the `Entry` the `Listbox` get closed. Use something like this: [making-a-pop-up-keyboard-in-tkinter-with-toplevel](https://stackoverflow.com/questions/22894937) – stovfl Jan 17 '20 at 10:20
  • Is there any way to bind "Up Button" so that while pressing "Up Button" dropdown will close and focus will back to ComboBox Entry? Usually by pressing "Up Button" main_focus changes from one data to another data but stops at the top of the dropdown, Is there any way to close dropdown if we again press "Up Button" then focus automatically come back to entry? – KK. Jan 17 '20 at 11:02
  • 1
    ***bind "Up Button"***: Unknow, these [Events](http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm) are available. – stovfl Jan 17 '20 at 11:21
  • Is there any way to close already opened dropdown of combobox by pressing any buttons(Not automatically)? – KK. Jan 17 '20 at 12:45
  • 1
    ***"by pressing any buttons"***: You are talking about `Button` but you mean `Keyboard Arrow Key`?? – stovfl Jan 17 '20 at 13:58
  • Sorry for confusion. Yes I mean Arrow Key, It's not working when Dropdown openes. I just want whenever focus at the top of the dropdown list, then by pressing "Up arrow key" focus return to editing mode(ComboBox Entry). Is it possible? we don't have any knowledge about dropdown frame since it's comes from internal functions. If we some how know the frame then we might get some ideas to close dropdown accords to our use... – KK. Jan 20 '20 at 05:28
  • Relevant [hide-and-show-ttk-combobox-dropdown-list](https://stackoverflow.com/questions/41666562/hide-and-show-ttk-combobox-dropdown-list) – stovfl Jan 22 '20 at 18:59
  • I just want to bind the after call **"source.after(delay, _source_delayed_clicked)"** with up arrow key, but seems like it's not possible because comboBox dropdown frame's coming from internally... – KK. Jan 24 '20 at 04:54
  • Related: https://stackoverflow.com/q/25588207/3372061 – Dev-iL Jan 18 '23 at 13:23

1 Answers1

3

Question: Show Combobox PopdownWindow, while editing text

This example extends a ttk.Combobox to the following:

  • Show the PopdownWindow while typing
  • Open the PopdownWindow on Key-pressed '<Down>'
  • Close the PopdownWindow on Key-pressed '<Up', if at the first item in the Listbox

Reference:


  1. Inherit from ttk.Combox

    import tkinter as tk
    import tkinter.ttk as ttk
    
    
    class Combobox(ttk.Combobox):
    
  2. Helper function, to map the internal Toplevel and Listbox to a tkinter object.

    WARNING: This uses Tk/Tcl internals, which could change without notice.
    This may working only with the tested Tk/Tcl version!

    def _tk(self, cls, parent):
        obj = cls(parent)
        obj.destroy()
        if cls is tk.Toplevel:
            obj._w = self.tk.call('ttk::combobox::PopdownWindow', self)
        else:
            obj._w = '{}.{}'.format(parent._w, 'f.l')
        return obj
    
  3. Initalize the object, get the internal references and bind to Key-press events

    def __init__(self, parent, **kwargs):
        super().__init__(parent, **kwargs)
        self.popdown = self._tk(tk.Toplevel, parent)
        self.listbox = self._tk(tk.Listbox, self.popdown)
    
        self.bind("<KeyPress>", self.on_keypress, '+')
        self.listbox.bind("<Up>", self.on_keypress)
    
  4. Key-pressed handler to show or hide the PopdownWindow and set the Keyboard focus.

    def on_keypress(self, event):
        if event.widget == self:
            state = self.popdown.state()
    
            if state == 'withdrawn' \
                    and event.keysym not in ['BackSpace', 'Up']:
                self.event_generate('<Button-1>')
                self.after(0, self.focus_set)
    
            if event.keysym == 'Down':
                self.after(0, self.listbox.focus_set)
    
        else:  # self.listbox
            curselection = self.listbox.curselection()
    
            if event.keysym == 'Up' and curselection[0] == 0:
                self.popdown.withdraw()
    
    

    Usage:

    class App(tk.Tk):
        def __init__(self):
            super().__init__()
    
            values = ('one', 'two', 'three', 'four', 'five', 'six', 'seven')
    
            self.cb = Combobox(self, value=values)
            self.cb.grid(row=0, column=0)
    
    
    if __name__ == "__main__":
        App().mainloop()
    
    

    Tested with Python: 3.5 - 'TclVersion': 8.6 'TkVersion': 8.6

stovfl
  • 14,998
  • 7
  • 24
  • 51
  • I'm not able to understand. Can you send me full code at once, it will be great help.Thanking You in advance. – KK. Feb 28 '20 at 06:34
  • @KK ***code at once,"***: Copy all code parts top down and run it. – stovfl Feb 28 '20 at 14:09
  • 1
    On my mac I had to set the delays in the two after methods to at least 20 ms. Lower than that and the focus wasn't reset to the Entry field. – Tls Chris Mar 21 '20 at 17:25
  • 1
    @TlsChris ***"MACOS"*** behaves different in certain points using `tkinter`. You can try to replace with `.after_idle(self....` without a timeout value. – stovfl Mar 21 '20 at 20:14
  • Thanks for the suggestion. The focus still ended up on the popdown! For what I'm doing even a 100ms delay in `after` doesn't seem to be a problem. How many people can type 10 meaningful characters in a second? – Tls Chris Mar 22 '20 at 14:35
  • @TlsChris ***"even a 100ms delay in after doesn't seem to be a problem"***: Consens with this, it's a timing issue. You can't change the focus while the current callback has not finished. – stovfl Mar 22 '20 at 14:41
  • @stovfl, my combobox list is not updating with this solution. I am using **trace('w', on_field_change)** and then after list update, I'm doing **combobox['values'] = listVar** but it's not working. Please tell me what do we have to change in class **Combobox**? – KK. Apr 29 '20 at 05:24
  • @KK ***I am using `trace('w',`...***: This is the same as `.bind(""`. Your `trace(...` break the `KeyPress` event. Try to add `on_field_change()` right after and inside `if event.widget == self:` – stovfl Apr 29 '20 at 07:47
  • @stovfl above solution is not working. Can you send a code which can modify combobox list as per the user_input? – KK. Apr 29 '20 at 13:16
  • Currently I can't run and verifying any Tkinter code. – stovfl Apr 29 '20 at 13:31