Search code examples
pythontkintercombobox

tkinter Combobox select next value instead of showing the whole list when pressing arrow keys


I have several tkinter Comboboxes in my python application with the default tkinter behaviour that the 'up' arrow does nothing and the 'down' arrow shows the whole list of values, which can then be reaverserd with the arrow keys.
However, I would like to 'scroll' through the Comboboxes with the arrow keys without this list popping up (i.e. arrow down directly switches to the next element, arrow up directly switches to the previous element).

MWE of Combobox:

import tkinter as tk
import tkinter.ttk as ttk

app = tk.Tk()
combo = ttk.Combobox(app, values = [f"item {i}" for i in range(20)])
combo.grid()

(How) can I achieve this desired behaviour? Do I have to catch the key events or is there some setting that I'm missing?


Solution

  • Here's a solution that should work for both Up and Down

    import tkinter as tk
    import tkinter.ttk as ttk
    
    
    def select_next(event):
        selection = combo.current()  # get the current selection
        last = len(combo['values']) - 1  # index of last item
        key = event.keysym  # get the key that was pressed
        if key == 'Up':
            try:
                combo.current(selection - 1)  # set the combobox to the previous item
            except tk.TclError:  # end of list reached
                combo.current(last)  # wrap around to last item
        elif key == 'Down':
            try:  
                combo.current(selection + 1)  # set the combobox to the next item
            except tk.TclError:  # end of list reached
                combo.current(0)   # wrap around to first item
        return 'break'  # tell tk to dispose of this event and don't show the menu!
    
    
    app = tk.Tk()
    combo = ttk.Combobox(app, values = [f"item {i}" for i in range(20)])
    combo.grid()
    combo.current(0)  # select the first item by default
    combo.bind('<Up>', select_next)  # up arrow
    combo.bind('<Down>', select_next)  # down arrow