簡體   English   中英

Python ttk.combobox 強制發布/打開

[英]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。

生成的 UI/UX

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM