Я видел много дискуссий о панели поиска, но я никогда не находил что-то действительно удобное. Я сделал пользовательский SearchBar (может быть, мы добавим это в tkinter, если он работает!).
Если вы попробуете этот код (Combobox), он позволит списку перекрывать другой виджет (поведение по умолчанию, я не мастер!), но вы не можете отобразить список И одновременно сохранить фокус на тексте, чтобы помочь пользователю:
import tkinter as tk
from tkinter import ttk
app=tk.Tk()
app_FRAME=tk.Frame(app,relief=tk.GROOVE)
app_FRAME.pack()
def clicked_on_arrow():
print("see the list")
def var_changed():
print("var changed")
_list = ["a","b","c"]
_var = tk.StringVar()
_var.trace("w", lambda name, index, mode, x=_var: var_changed())
_COMBOBOX = ttk.Combobox(app_FRAME, postcommand=clicked_on_arrow(), values=_list, textvariable=_var)
_COMBOBOX.pack()
random_BUTTON = tk.Button(app_FRAME, text="the list can overlap over me !")
random_BUTTON.pack(fill=tk.BOTH, expand=True)
app.mainloop()
Этот код (более сложный и настраиваемый) не может перекрываться ( потому что я не совсем уверен, как реализовать его для создания собственного виджета, не зная фрейма root), но он действительно помогает пользователю, визуализируя список в режиме реального времени:
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 9 17:25:59 2020
@author: aymeric LAUGEL
"""
import tkinter as tk
class Search_Bar:
def create_new_list(self,string_given, string_list):
new_list = []
for string in string_list:
if(len(string_given) <=len(string)):
if(string.find(string_given) != -1):
new_list.append(string)
return new_list
def update_display_list(self):
if(self.listboxExist):
self.m_LISTBOX.delete(0,tk.END)
for string in self.m_list_to_display: self.m_LISTBOX.insert('end', string)
else:
print("listbox should exist...")
def maybe_update_display_LISTBOX(self):
possible_new_list_to_display = self.create_new_list(self.m_text_entry_object.get(), self.m_list)
print()
print("#############")
print("LISTBOX exist:",self.listboxExist)
print("var: |"+self.m_text_entry_object.get()+"|")
print("old list:",self.m_list_to_display)
print("new list:",possible_new_list_to_display)
if(len(possible_new_list_to_display) == 0):
print("nothing to display")
if(self.listboxExist):
self.delete_LISTBOX()
else:
print("La listbox n'existe déjà plus")
return
if possible_new_list_to_display == self.m_list_to_display:
print("list are the same, no need to update")
if(self.listboxExist):
pass
else:
self.create_LISTBOX()
print("Listbox should already exist cause length is more than 0...")
return
if(len(possible_new_list_to_display) == len(self.m_list_to_display)):
print("just need to update the values, not the length")
self.m_list_to_display = possible_new_list_to_display
if(self.listboxExist):
self.update_display_list()
else:
print("Listbox should have already been created.")
self.create_LISTBOX()
return
if(len(possible_new_list_to_display) >= self.m_max_element_to_display and
len(self.m_list_to_display) >= self.m_max_element_to_display):
print("not the same len but we are gonna display the max number of row anyway")
self.m_list_to_display = possible_new_list_to_display
if(self.listboxExist):
self.update_display_list()
else:
if not(self.itemInListboxSelected):
print("Listbox should have already been created....")
self.create_LISTBOX()
return
print("we have to change the length of the LISTBOX display (and the values)")
self.m_list_to_display = possible_new_list_to_display
if(self.listboxExist):
self.delete_LISTBOX()
self.create_LISTBOX()
def func_called_when_text_change(self,event):
print("the text changed")
self.maybe_update_display_LISTBOX()
def focus_in_ENTRY(self, event):
print("focus in ENTRY")
self.focusIn_ENTRY = True
self.maybe_create_LISTBOX()
def focus_out_ENTRY(self, event):
print("focus out ENTRY")
self.focusIn_ENTRY = False
self.maybe_delete_LISTBOX()
def cursor_in_ENTRY(self, event):
print("cursor in ENTRY")
self.cursorIn_ENTRY = True
def cursor_out_ENTRY(self, event):
print("cursor out ENTRY")
self.cursorIn_ENTRY = False
def focus_in_LISTBOX(self, event):
print("focus in LISTBOX")
self.focusIn_LISTBOX = True
def focus_out_LISTBOX(self, event):
print("focus out LISTBOX")
self.focusIn_LISTBOX = False
self.maybe_delete_LISTBOX()
def cursor_in_LISTBOX(self, event):
print("cursor in LISTBOX")
self.cursorIn_LISTBOX = True
def cursor_out_LISTBOX(self, event):
print("cursor out LISTBOX")
self.cursorIn_LISTBOX = False
def maybe_create_LISTBOX(self):
if(self.focusIn_ENTRY == True and self.listboxExist == False):
self.create_LISTBOX()
def maybe_delete_LISTBOX(self):
if(#self.focusIn_ENTRY == False and
self.listboxExist == True and
self.cursorIn_LISTBOX == False and
self.cursorIn_ENTRY == False):
self.delete_LISTBOX()
def item_selected(self,event):
print("an item have been selected from the listbox")
self.itemInListboxSelected = True
selected_item_tuple_id = self.m_LISTBOX.curselection()
if(selected_item_tuple_id != ()):
string = str(self.m_LISTBOX.get(self.m_LISTBOX.curselection()))
self.m_text_entry_object.set(string)
self.m_list_to_display = []
self.delete_LISTBOX()
self.itemInListboxSelected = False
def create_LISTBOX(self):
print("we create the listbox")
if(self.listboxExist):
print("Listbox should not be here")
return
if(self.m_LISTBOX != None):
print("THE LIST SHOULD HAVE BEEN ABSENT !!!")
return
if(len(self.m_list_to_display) == 0):
print("We shouldn't try to display an empty listbox...")
return
if(self.m_max_element_to_display > len(self.m_list_to_display)):
nbr_of_row_to_display = len(self.m_list_to_display)
else:
nbr_of_row_to_display = self.m_max_element_to_display
self.m_LISTBOX = tk.Listbox(self.m_FRAME, height=nbr_of_row_to_display)
self.m_LISTBOX.pack()
self.m_LISTBOX.bind("<FocusIn>", self.focus_in_LISTBOX)
self.m_LISTBOX.bind("<FocusOut>", self.focus_out_LISTBOX)
self.m_LISTBOX.bind("<Enter>", self.cursor_in_LISTBOX)
self.m_LISTBOX.bind("<Leave>", self.cursor_out_LISTBOX)
self.m_LISTBOX.bind('<<ListboxSelect>>', self.item_selected)
self.listboxExist = True
self.update_display_list()
def delete_LISTBOX(self):
print("we delete the listbox")
if not(self.listboxExist):
print("Listbox should be here")
return
if(self.m_LISTBOX == None):
print("THE LIST SHOULD HAVE BEEN PRESENT !!!")
return
self.m_LISTBOX.destroy()
del self.m_LISTBOX
self.m_LISTBOX = None
self.list_to_display = []
self.listboxExist = False
def __init__(self, actual_FRAME, _list, max_element_to_display=4):
self.itemInListboxSelected = False
self.focusIn_ENTRY = False
self.cursorIn_ENTRY = False
self.cursorIn_LISTBOX = False
self.listboxExist = False
self.m_list = _list
if(max_element_to_display > len(_list)):
print("vous ne pouvez pas display plus d'éléments qu'il y en a dans la list...")
self.m_max_len_to_display = len(_list)
self.m_max_element_to_display = max_element_to_display
self.m_list_to_display = self.m_list
self.m_FRAME = actual_FRAME
self.m_text_entry_object = tk.StringVar()
self.m_text_entry_object.trace("w", lambda name, index, mode, x=self.m_text_entry_object: self.func_called_when_text_change(x))
self.m_ENTRY = tk.Entry(self.m_FRAME, textvariable=self.m_text_entry_object)
self.m_ENTRY.pack(side = tk.TOP)
self.m_ENTRY.bind("<FocusIn>", self.focus_in_ENTRY)
self.m_ENTRY.bind("<FocusOut>", self.focus_out_ENTRY)
self.m_ENTRY.bind("<Enter>", self.cursor_in_ENTRY)
self.m_ENTRY.bind("<Leave>", self.cursor_out_ENTRY)
self.m_LISTBOX = None
#self.create_LISTBOX()
#self.m_FRAME.pack_propagate(0)
#self.delete_LISTBOX()
if __name__ == "__main__":
app=tk.Tk()
app.geometry('500x300')
_list = ["fruit de la passion", "pomme","poire","pêche","abricot","pamplemousse","orange","raisin","cassis"]
search_bar_FRAME=tk.Frame(app,relief=tk.GROOVE, borderwidth=5)
search_bar_FRAME.pack(side=tk.TOP,expand=True)
SEARCH_BAR = Search_Bar(search_bar_FRAME, _list, max_element_to_display=5)
_list_2 = ["amour","gloire","pouvoir de l'instant présent","beauté","guerre","action"]
search_bar_2_FRAME=tk.Frame(app,relief=tk.GROOVE, borderwidth=5)
search_bar_2_FRAME.pack(side=tk.TOP)
SEARCH_BAR_2 = Search_Bar(search_bar_2_FRAME, _list_2, max_element_to_display=3)
other_FRAME=tk.Frame(app,relief=tk.GROOVE, borderwidth=5)
other_FRAME.pack()
_random_Button = tk.Button(other_FRAME, text="This search bar can't overlap over me...")
_random_Button.pack(side=tk.LEFT)
app.mainloop()
Мой вопрос :
Как перекрывать другие виджеты списком, например списком со списком, но все же помогать пользователю, когда он печатает что-то, показывая список?
Надеюсь, у меня все ясно, вы можете запустить 2 отдельные коды, чтобы увидеть плюсы и минусы.
Любые советы, примеры или помощь приветствуется! :)
Может быть, как настроить Combobox, потому что он почти у цели!
В других темах говорится о чем-то, что может помочь: