[英]Changing values of a ttk.Combobox by using ttk.Radiobuttons - Python
[英]Python ttk.combobox force post/open
我正在嘗試擴展 ttk combobox class 以允許自我暗示。 我目前使用的代碼運行良好,但我想讓它在輸入一些文本后顯示下拉列表,而不從小部件的輸入部分移除焦點。
我正在努力的部分是找到一種方法來強制下拉,在 python 文檔中我找不到任何提及,但是在 tk 文檔中我確實找到了一個我認為應該這樣做的 post 方法,除了它沒有' t 似乎在 python 包裝器中實現。
我也嘗試在自動提示發生后生成一個向下箭頭鍵事件,但是雖然這確實顯示了下拉菜單,但它會刪除焦點,並且在此事件之后嘗試設置焦點似乎也不起作用(焦點不會返回)
有誰知道我可以用來實現這個目標的 function 嗎?
我擁有的代碼適用於 python 3.3,僅使用標准庫:
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 = None
def 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"]:
return
self.autoid = self.after(200, self.AutoComplete_2)
def AutoComplete_2(self):
data = self.get()
if data != "":
for entry in self["values"]:
match = True
try:
for index in range(0, len(data)):
if data[index] != entry[index]:
match = False
break
except IndexError:
match = False
if match == True:
self.set(entry)
self.selection_range(len(data), "end")
self.event_generate("<Down>",when="tail")
self.focus_set()
break
self.autoid = None
您不需要為此事件繼承ttk.Combobox; 只需使用event_generate強制下拉:
box = Combobox(...)
def callback(box):
box.event_generate('<Down>')
下面演示了使用工具提示實現此 UX 的解決方法。 這是使用PySimpleGUI
實現的,但應該很容易適應“純”tkinter。
from functools import partial
from typing import Callable, Any
from 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 = None
def show_combo_tooltip(ui_handle: sg.Element, tooltip: str) -> None:
ui_handle.set_tooltip(tooltip)
tt = ui_handle.TooltipObject
tt.y += 40
tt.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)
return
matches = 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 focus
clear_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'):
break
callbacks.get(event, unhandled_event_callback)(values)
# SG: Cleanup
window.close()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.