Python ttk.combobox force post/open

2024/9/20 9:29:25

I am trying to extend the ttk combobox class to allow autosuggestion. the code I have far works well, but I would like to get it to show the dropdown once some text has been entered without removing focus from the entry part of the widget.

The part I am struggling with is finding a way to force the dropdown, in the python docs I cannot find any mention of this, however in the tk docs I did find a post method I believe is supposed to do this, except it doesn't seem to be implemented in the python wrapper.

I also tried generating a down arrow key event once the autosuggest has taken place, however while this does show the dropdown it removes focus, and trying to set the focus after this event doesn't seem to work either (focus does not return)

Is anyone aware of a function I can use to achieve this?

The code I have is for python 3.3 using only standard libs:

class AutoCombobox(ttk.Combobox):def __init__(self, parent, **options):ttk.Combobox.__init__(self, parent, **options)self.bind("<KeyRelease>", self.AutoComplete_1)self.bind("<<ComboboxSelected>>", self.Cancel_Autocomplete)self.bind("<Return>", self.Cancel_Autocomplete)self.autoid = Nonedef Cancel_Autocomplete(self, event=None):self.after_cancel(self.autoid) def AutoComplete_1(self, event):if self.autoid != None:self.after_cancel(self.autoid)if event.keysym in ["BackSpace", "Delete", "Return"]:returnself.autoid = self.after(200, self.AutoComplete_2)def AutoComplete_2(self):data = self.get()if data != "":for entry in self["values"]:match = Truetry:for index in range(0, len(data)):if data[index] != entry[index]:match = Falsebreakexcept IndexError:match = Falseif match == True:self.set(entry)self.selection_range(len(data), "end")self.event_generate("<Down>",when="tail")self.focus_set()breakself.autoid = None
Answer

A workaround that achieves this UX using tooltips is demonstrated below. This is implemented using PySimpleGUI, but should be easily adaptable to "pure" tkinter.

Resulting UI/UX

from functools import partial
from typing import Callable, Anyfrom fuzzywuzzy import process, fuzz
import PySimpleGUI as sg# SG: Helper functions:
def clear_combo_tooltip(*_, ui_handle: sg.Element, **__) -> None:if tt := ui_handle.TooltipObject:tt.hidetip()ui_handle.TooltipObject = Nonedef show_combo_tooltip(ui_handle: sg.Element, tooltip: str) -> None:ui_handle.set_tooltip(tooltip)tt = ui_handle.TooltipObjecttt.y += 40tt.showtip()def symbol_text_updated(event_data: dict[str, Any], all_values: list[str], ui_handle: sg.Element) -> None:new_text = event_data[ui_handle.key]if new_text == '':ui_handle.update(values=all_values)returnmatches = process.extractBests(new_text, all_values, scorer=fuzz.ratio, score_cutoff=40)sym = [m[0] for m in matches]ui_handle.update(new_text, values=sym)# tk.call('ttk::combobox::Post', ui_handle.widget)  # This opens the list of options, but takes focusclear_combo_tooltip(ui_handle=ui_handle)show_combo_tooltip(ui_handle=ui_handle, tooltip="\n".join(sym))# Prepare data:
all_symbols = ["AAPL", "AMZN", "MSFT", "TSLA", "GOOGL", "BRK.B", "UNH", "JNJ", "XOM", "JPM", "META", "PG", "NVDA", "KO"]# SG: Layout
sg.theme('DarkAmber')
layout = [[sg.Text('Symbol:'),sg.Combo(all_symbols, enable_per_char_events=True, key='-SYMBOL-')]
]# SG: Window
window = sg.Window('Symbol data:', layout, finalize=True)
window['-SYMBOL-'].bind("<Key-Down>", "KeyDown")# SG: Event loop
callbacks: dict[str: Callable] = {'-SYMBOL-': partial(symbol_text_updated, all_values=all_symbols, ui_handle=window['-SYMBOL-']),'-SYMBOL-KeyDown': partial(clear_combo_tooltip, ui_handle=window['-SYMBOL-']),
}
unhandled_event_callback = partial(lambda x: print(f"Unhandled event key: {event}. Values: {x}"))while True:event, values = window.read()if event in (sg.WIN_CLOSED, 'Exit'):breakcallbacks.get(event, unhandled_event_callback)(values)# SG: Cleanup
window.close()

This solution was inspired by this gist and this discussion.

https://en.xdnf.cn/q/72514.html

Related Q&A

How to pull from the remote using dulwich?

How to do something like git pull in python dulwich library.

convert python programme to windows executable

i m trying to create windows executable from python program which has GUI . i m using following scriptfrom distutils.core import setup import py2exesetup(console=[gui.py]) it gives following errorWarni…

Must explicitly set engine if not passing in buffer or path for io in Panda

When running the following Python Panda code:xl = pd.ExcelFile(dataFileUrl)sheets = xl.sheet_namesdata = xl.parse(sheets[0])colheaders = list(data)I receive the ValueError:Must ex…

How to access the keys or values of Python GDB Value

I have a struct in GDB and want to run a script which examines this struct. In Python GDB you can easily access the struct via(gdb) python mystruct = gdb.parse_and_eval("mystruct")Now I got t…

How can I fire a Traits static event notification on a List?

I am working through the traits presentation from PyCon 2010. At about 2:30:45 the presenter starts covering trait event notifications, which allow (among other things) the ability to automatically ca…

Calculate moving average in numpy array with NaNs

I am trying to calculate the moving average in a large numpy array that contains NaNs. Currently I am using:import numpy as npdef moving_average(a,n=5):ret = np.cumsum(a,dtype=float)ret[n:] = ret[n:]-r…

Python: numpy.insert NaN value

Im trying to insert NaN values to specific indices of a numpy array. I keep getting this error:TypeError: Cannot cast array data from dtype(float64) to dtype(int64) according to the rule safeWhen tryin…

Identify external workbook links using openpyxl

I am trying to identify all cells that contain external workbook references, using openpyxl in Python 3.4. But I am failing. My first try consisted of:def find_external_value(cell): # identifies an e…

3D-Stacked 2D histograms

I have a bunch of 2D histograms (square 2D numpy arrays) that I want to stack in 3D like so:(Image from: Cardenas, Alfredo E., et al. "Unassisted transport of N-acetyl-L-tryptophanamide through me…

Python and mySQLdb error: OperationalError: (1054, Unknown column in where clause)

Hey all, Im getting an error OperationalError: (1054, "Unknown column XX in where clause")Where XX is the value of CLASS in the following codeconn = MySQLdb.connect(host = "localhost&quo…