300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Python tkinter自定义多选下拉列表框(带滚动条 全选)

Python tkinter自定义多选下拉列表框(带滚动条 全选)

时间:2022-07-12 02:31:59

相关推荐

Python tkinter自定义多选下拉列表框(带滚动条 全选)

Python tkinter自定义多选下拉列表框

1、demo.py文件2、ComBoPicker.py文件3、ComBoPicker1.py文件4、效果

上一篇文章,很多小伙伴不知道怎么加全选和滚动条,所以做出的修改,增加全选和滚动条,如果有不足之处,欢迎指出,感谢!

1、demo.py文件

from tkinter import *from ComBoPicker import Combopicker# 导入自定义下拉多选框from ComBoPicker1 import Combopicker as Combopicker1# 导入自定义下拉多选框if __name__ == "__main__":root = Tk()root.geometry("300x300")F =Frame(root)F.pack(expand=False, fill="both",padx=10,pady=10)Label(F,text='全选、可滚动:').pack(side='left')COMBOPICKER = Combopicker(F, values = ['全选','项目1','项目2','项目3','项目4','项目5','项目11','项目22','项目33','项目44','项目55'])COMBOPICKER.pack(anchor="w")F2 =Frame(root)F2.pack(expand=False, fill="both",padx=10,pady=10)Label(F2,text='普通:').pack(side='left')COMBOPICKER1 = Combopicker1(F2, values = [f'项目{i}' for i in range(5)])COMBOPICKER1.pack(anchor="w")root.mainloop()

2、ComBoPicker.py文件

'''自定义多选下拉列表'''# import tkinter.font as tkFontimport tkinter.ttk as ttkfrom tkinter import LabelFrame,IntVar,StringVar,Canvasclass Picker(ttk.Frame):def __init__(self, master=None, activebackground='#b1dcfb', values=[], entry_wid=None, activeforeground='black',selectbackground='#003eff', selectforeground='white', command=None, borderwidth=1, relief="solid"):self._selected_item = Noneself._values = valuesself._entry_wid = entry_widself._sel_bg = selectbackground self._sel_fg = selectforegroundself._act_bg = activebackground self._act_fg = activeforegroundself._command = commandself.index=0ttk.Frame.__init__(self, master, borderwidth=borderwidth,height=10, relief=relief)self.bind("<FocusIn>", lambda event:self.event_generate('<<PickerFocusIn>>'))self.bind("<FocusOut>", lambda event:self.event_generate('<<PickerFocusOut>>'))F = LabelFrame(self)F.pack(fill='x')self.canvas = Canvas(F,scrollregion=(0,0,500,(len(self._values)*21)))vbar = ttk.Scrollbar(F,orient='vertical')vbar.pack(side='right',fill='y')frame = ttk.Frame(self.canvas)vbar.config(command=self.canvas.yview)# self.canvas.pack(side='left',fill='x',expand=True)self.canvas.create_window((0,0,),window=frame,anchor='nw',tags='frame')self.canvas.config(highlightthickness=0) # 去掉选中边框vbar.config(command=self.canvas.yview)self.canvas.config(width=300,height=150)self.canvas.config(yscrollcommand=vbar.set)# self.canvas.config(scrollregion=self.canvas.bbox('all'))# self._font = tkFont.Font()self.dict_checkbutton = {}self.dict_checkbutton_var = {}self.dict_intvar_item = {}for index,item in enumerate(self._values):self.dict_intvar_item[item] = IntVar()self.dict_checkbutton[item] = ttk.Checkbutton(frame, text = item, variable=self.dict_intvar_item[item],command=lambda ITEM = item:self._command(ITEM))self.dict_checkbutton[item].grid(row=index, column=0, sticky='nsew',padx=5)self.dict_intvar_item[item].set(0)if item in self._entry_wid.get().split(','):self.dict_intvar_item[item].set(1)self.canvas.pack(side='left',expand=True,fill='both')self.canvas.bind("<MouseWheel>",self.processWheel)frame.bind("<MouseWheel>",self.processWheel)for i in self.dict_checkbutton:self.dict_checkbutton[i].bind("<MouseWheel>",self.processWheel)self.bind("<MouseWheel>",self.processWheel)def processWheel(self,event):index = int(-(event.delta))if index > 0:self.canvas.yview_scroll(2,'units')else:self.canvas.yview_scroll(-2, 'units')class Combopicker(ttk.Entry, Picker):def __init__(self, master, values=[], entryvar=None, entrywidth=None, entrystyle=None, onselect=None,activebackground='#b1dcfb', activeforeground='black', selectbackground='#003eff', selectforeground='white', borderwidth=1, relief="solid", state='normal'):self.values=valuesself.master=masterself.activeforeground=activeforegroundself.activebackground=activebackgroundself.selectbackground=selectbackgroundself.selectforeground=selectforegroundif entryvar is not None:self.entry_var = entryvarelse:self.entry_var = StringVar()entry_config = {}if entrywidth is not None:entry_config["width"] = entrywidthif entrystyle is not None:entry_config["style"] = entrystylettk.Entry.__init__(self, master,textvariable=self.entry_var, **entry_config, state=state)self._is_menuoptions_visible = Falseself.picker_frame = Picker(self.winfo_toplevel(), values=values,entry_wid = self.entry_var,activebackground=activebackground, activeforeground=activeforeground, selectbackground=selectbackground, selectforeground=selectforeground, command=self._on_selected_check)self.bind_all("<1>", self._on_click, "+")self.bind("<Escape>", lambda event: self.hide_picker())@propertydef current_value(self):try:value = self.entry_var.get()return valueexcept ValueError:return None@current_value.setterdef current_value(self, INDEX):self.entry_var.set(self.values.index(INDEX))def _on_selected_check(self, SELECTED):value = []all_name = '全选'if self.entry_var.get() != "" and self.entry_var.get() != None:temp_value = self.entry_var.get()value = temp_value.split(",")if str(SELECTED) in value: if all_name == str(SELECTED):value.clear() # 清空选项else:if all_name in value:value.remove(all_name)value.remove(str(SELECTED))value.sort()else: if all_name == str(SELECTED):value = self.valueselse:value.append(str(SELECTED))value.sort()temp_value = ""for index,item in enumerate(value):if item!= "":if index != 0:temp_value += ","temp_value += str(item)self.entry_var.set(temp_value)# 可以通过复选框的variable来让勾选中或取消,但下面也行,问题不大# 刷新if all_name == str(SELECTED):self.hide_picker()self.show_picker()def _on_click(self, event):str_widget = str(event.widget)if str_widget == str(self):if not self._is_menuoptions_visible:self.show_picker()else:if not str_widget.startswith(str(self.picker_frame)) and self._is_menuoptions_visible:self.hide_picker()def show_picker(self):if not self._is_menuoptions_visible:self.picker_frame = Picker(self.winfo_toplevel(), values=self.values,entry_wid = self.entry_var,activebackground=self.activebackground,activeforeground=self.activeforeground, selectbackground=self.selectbackground, selectforeground=self.selectforeground, command=self._on_selected_check)self.bind_all("<1>", self._on_click, "+")self.bind("<Escape>", lambda event: self.hide_picker())self.picker_frame.lift()self.picker_frame.place(in_=self, relx=0, rely=1, relwidth=1 )self._is_menuoptions_visible = Truedef hide_picker(self):if self._is_menuoptions_visible:self.picker_frame.place_forget() # 不知道为什么这个方式在mac下不起作用,所以就直接销毁这个控件# self.picker_frame.destroy()self._is_menuoptions_visible = False

3、ComBoPicker1.py文件

'''自定义多选下拉列表'''import tkinter.font as tkFontimport tkinter.ttk as ttkfrom tkinter import *class Picker(ttk.Frame):def __init__(self, master=None,activebackground='#b1dcfb',values=[],entry_wid=None,activeforeground='black', selectbackground='#003eff', selectforeground='white', command=None, borderwidth=1, relief="solid"):self._selected_item = Noneself._values = valuesself._entry_wid = entry_widself._sel_bg = selectbackground self._sel_fg = selectforegroundself._act_bg = activebackground self._act_fg = activeforegroundself._command = commandttk.Frame.__init__(self, master, borderwidth=borderwidth, relief=relief)self.bind("<FocusIn>", lambda event:self.event_generate('<<PickerFocusIn>>'))self.bind("<FocusOut>", lambda event:self.event_generate('<<PickerFocusOut>>'))self._font = tkFont.Font()self.dict_checkbutton = {}self.dict_checkbutton_var = {}self.dict_intvar_item = {}for index,item in enumerate(self._values):self.dict_intvar_item[item] = IntVar()self.dict_checkbutton[item] = ttk.Checkbutton(self, text = item, variable=self.dict_intvar_item[item],command=lambda ITEM = item:self._command(ITEM))self.dict_checkbutton[item].grid(row=index, column=0, sticky=NSEW)self.dict_intvar_item[item].set(0)class Combopicker(ttk.Entry, Picker):def __init__(self, master, values= [] ,entryvar=None, entrywidth=None, entrystyle=None, onselect=None,activebackground='#b1dcfb', activeforeground='black', selectbackground='#003eff', selectforeground='white', borderwidth=1, relief="solid"):self.values=valuesif entryvar is not None:self.entry_var = entryvarelse:self.entry_var = StringVar()entry_config = {}if entrywidth is not None:entry_config["width"] = entrywidthif entrystyle is not None:entry_config["style"] = entrystylettk.Entry.__init__(self, master, textvariable=self.entry_var, **entry_config, state = "readonly")self._is_menuoptions_visible = Falseself.picker_frame = Picker(self.winfo_toplevel(), values=values,entry_wid = self.entry_var,activebackground=activebackground, activeforeground=activeforeground, selectbackground=selectbackground, selectforeground=selectforeground, command=self._on_selected_check)self.bind_all("<1>", self._on_click, "+")self.bind("<Escape>", lambda event: self.hide_picker())@propertydef current_value(self):try:value = self.entry_var.get()return valueexcept ValueError:return None@current_value.setterdef current_value(self, INDEX):self.entry_var.set(self.values.index(INDEX))def _on_selected_check(self, SELECTED):value = []if self.entry_var.get() != "" and self.entry_var.get() != None:temp_value = self.entry_var.get()value = temp_value.split(",")if str(SELECTED) in value:value.remove(str(SELECTED))else: value.append(str(SELECTED))value.sort()temp_value = ""for index,item in enumerate(value):if item!= "":if index != 0:temp_value += ","temp_value += str(item)self.entry_var.set(temp_value)def _on_click(self, event):str_widget = str(event.widget)if str_widget == str(self):if not self._is_menuoptions_visible:self.show_picker()else:if not str_widget.startswith(str(self.picker_frame)) and self._is_menuoptions_visible:self.hide_picker()def show_picker(self):if not self._is_menuoptions_visible:self.picker_frame.place(in_=self, relx=0, rely=1, relwidth=1 )self.picker_frame.lift()self._is_menuoptions_visible = Truedef hide_picker(self):if self._is_menuoptions_visible:self.picker_frame.place_forget()self._is_menuoptions_visible = False

4、效果

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。