from tkinter import Entry, Frame, Listbox, Scrollbar, StringVar, Tk, Toplevel
from tkinter.constants import END, EW, HORIZONTAL, NS
def singleton(cls, *args, **kwargs):
instances = {}
def _singleton():
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return _singleton
@singleton
class ListBox(object):
"""ListBox Class"""
def __init__(self):
self.top_window = None
def init(self, width):
self.width = width
def show(self, p_master, values, master):
self.p_master = p_master
self.master = master
self.values = values
if self.top_window:
return
x = self.master.winfo_rootx()
y = self.master.winfo_rooty() + self.master.winfo_height()
self.top_window = Toplevel(self.master)
self.top_window.wm_overrideredirect(1)
self.top_window.wm_geometry("+%d+%d" % (x, y))
self.top_window.bind('<Configure>', self.on_change_geometry)
self.top_window.bind_all("<Button-1>", self.on_gloabl_click)
self.sb_y = Scrollbar(self.top_window)
self.sb_x = Scrollbar(self.top_window, orient=HORIZONTAL)
self.sb_x.grid(row=1, column=0, sticky=EW)
self.list_box = Listbox(self.top_window,
xscrollcommand=self.sb_x.set,
yscrollcommand=self.sb_y.set,
width=self.width)
for data in self.values:
self.list_box.insert(END, data)
if self.p_master.input_var.get() != '' and self.p_master.input_var.get() in self.values:
index = self.values.index(self.p_master.input_var.get())
else:
index = 0
self.list_box.select_set(index)
self.list_box.bind("<ButtonRelease-1>", self.on_click_item)
self.sb_x.config(command=self.list_box.xview)
self.sb_y.config(command=self.list_box.yview)
self.sb_y.grid(row=0, column=1, sticky=NS)
self.sb_x.grid(row=1, column=0, sticky=EW)
self.list_box.grid(row=0, column=0)
def on_gloabl_click(self, event):
if isinstance(event.widget, Listbox) or isinstance(
event.widget, Scrollbar):
pass
else:
self.hide()
def hide(self):
if self.top_window:
if self.p_master.input_var.get() == '' or self.p_master.input_var.get() not in self.values:
self.p_master.input_var.set(self.list_box.get(0))
self.p_master.entry.icursor(len(self.p_master.input_var.get()))
self.top_window.destroy()
self.top_window = None
def on_change_geometry(self, event):
x = self.master.winfo_rootx()
y = self.master.winfo_rooty() + self.master.winfo_height()
self.top_window.wm_geometry("+%d+%d" % (x, y))
def on_click_item(self, event):
self.p_master.input_var.set(
self.list_box.get(self.list_box.curselection()))
self.hide()
def update_list(self):
datas = []
for value in self.values:
if self.p_master.input_var.get() in value:
datas.append(value)
self.list_box.delete(0, END)
if len(datas) == 0 and self.p_master.input_var.get() == '':
datas = self.values
elif len(datas) == 0 and self.p_master.input_var.get() != '' and self.p_master.input_var.get() not in self.values:
datas = self.values
else:
pass
for data in datas:
self.list_box.insert(END, data)
def is_show(self):
if self.top_window and self.top_window.state() == 'normal':
return True
else:
return False
class ComboBox(object):
"""ComboBox Class"""
def __init__(self, values, width, master=None):
self.master = master
self.values = values
self.frame = Frame(self.master)
self.frame.grid(row=0, column=0)
self.input_var = StringVar()
self.input_var.set(self.values[0])
self.entry = Entry(self.frame, textvariable=self.input_var, width=width)
self.entry.grid()
self.entry.bind('<KeyRelease>', self.on_update_list)
self.entry.bind('<ButtonRelease-1>', self.on_entry_click)
self.entry.bind('<Return>', self.on_enter)
ListBox().init(width)
def on_enter(self, event):
if self.input_var.get() in self.values:
pass
else:
self.input_var.set(self.values[0])
self.entry.icursor(len(self.input_var.get()))
def on_entry_click(self, event):
if ListBox().is_show():
ListBox().hide()
else:
ListBox().show(self, self.values, self.entry)
def on_update_list(self, event):
if ListBox().is_show():
ListBox().update_list()
root = Tk()
root.geometry("800x480")
root.title("ComboBox")
root.bind_all('<Button-1>')
data = []
for index in range(1000):
data.append(str(index))
frame = Frame(root, width=800, height=480)
frame.grid(row=0, column=0)
frame.grid_propagate(0)
frame1 = Frame(frame, width=800, height=35)
frame1.grid(row=0, column=0)
ComboBox(data, 35, frame1)
frame2 = Frame(frame, width=800, height=35)
frame2.grid(row=1, column=0)
ComboBox(data, 35, frame2)
root.mainloop()
Python tkinter 自定义筛选下拉框
最新推荐文章于 2024-05-29 14:11:57 发布