tkinter自定義下拉多選框問題
更新時(shí)間:2023年01月28日 10:17:12 作者:奮斗中的打工人
這篇文章主要介紹了tkinter自定義下拉多選框問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
使用tkinter實(shí)現(xiàn)下拉多選框
效果如圖:
1、選擇一些選項(xiàng)

2、全選選項(xiàng)

代碼如下:
import tkinter
from ComBoPicker import Combopicker
list = ["全選", "選項(xiàng)1", "選項(xiàng)2", "選項(xiàng)3", "選項(xiàng)4", "選項(xiàng)5", "選項(xiàng)6"]
root = tkinter.Tk()
co = Combopicker(root, values=list)
co.pack()
root.geometry("800x600")
root.mainloop()ComBoPicker.py代碼:
'''
自定義多選下拉列表
'''
import tkinter.ttk as ttk
from 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 = None
self._values = values
self._entry_wid = entry_wid
self._sel_bg = selectbackground
self._sel_fg = selectforeground
self._act_bg = activebackground
self._act_fg = activeforeground
self._command = command
self.index = 0
ttk.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) * 23)))
vbar = Scrollbar(F, orient=VERTICAL)
vbar.pack(side=RIGHT, fill=Y)
frame = Frame(self.canvas) #創(chuàng)建框架
vbar.config(command=self.canvas.yview)
sbar2 = Scrollbar(F, orient=HORIZONTAL)
sbar2.pack(side=BOTTOM, fill=X)
sbar2.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)
sbar2.config(command=self.canvas.xview)
self.canvas.config(width=300, height=150)
self.canvas.config(yscrollcommand=vbar.set,xscrollcommand=sbar2.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):
a = int(-(event.delta))
if a > 0:
self.canvas.yview_scroll(1, UNITS)
else:
self.canvas.yview_scroll(-1, UNITS)
class Combopicker(ttk.Combobox, Picker):
def __init__(self, master, values=[], entryvar=None, entrywidth=None, entrystyle=None, onselect=None,
activebackground='#ef476f', activeforeground='red', selectbackground='#ffd166',
selectforeground='green', borderwidth=1, relief="solid"):
self.values = values
self.master = master
self.activeforeground = activeforeground
self.activebackground = activebackground
self.selectbackground = selectbackground
self.selectforeground = selectforeground
if entryvar is not None:
self.entry_var = entryvar
else:
self.entry_var = StringVar()
entry_config = {}
if entrywidth is not None:
entry_config["width"] = entrywidth
if entrystyle is not None:
entry_config["style"] = entrystyle
ttk.Entry.__init__(self, master, textvariable=self.entry_var, **entry_config, state="")
self._is_menuoptions_visible = False
self.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())
@property
def current_value(self):
try:
value = self.entry_var.get()
return value
except ValueError:
return None
@current_value.setter
def 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:
if '全選' == str(SELECTED):
value.clear() # 清空選項(xiàng)
else:
value.remove(str(SELECTED))
value.sort()
else:
if '全選' == str(SELECTED):
value = self.values
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)
# 可以通過復(fù)選框的variable來讓勾選中或取消,但下面也行,問題不大
if '全選' == 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 = True
def hide_picker(self):
if self._is_menuoptions_visible:
self.picker_frame.place_forget() # 不知道為什么這個方式在mac下不起作用,所以就直接銷毀這個控件
# self.picker_frame.destroy()
self._is_menuoptions_visible = False總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Django?Rest?Framework實(shí)現(xiàn)身份認(rèn)證源碼詳解
這篇文章主要為大家介紹了Django?Rest?Framework實(shí)現(xiàn)身份認(rèn)證源碼詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
使用Scrapy框架爬取網(wǎng)頁并保存到Mysql的實(shí)現(xiàn)
本文主要介紹了使用Scrapy框架爬取網(wǎng)頁并保存到Mysql的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
python3 requests庫文件上傳與下載實(shí)現(xiàn)詳解
這篇文章主要介紹了python3 requests庫文件上傳與下載實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
Python中關(guān)于函數(shù)的具體用法范例以及介紹
函數(shù)是組織好的,可重復(fù)使用的,用來實(shí)現(xiàn)單一,或相關(guān)聯(lián)功能的代碼段。函數(shù)能提高應(yīng)用的模塊性,和代碼的重復(fù)利用率。你已經(jīng)知道Python提供了許多內(nèi)建函數(shù),比如print()。但你也可以自己創(chuàng)建函數(shù),這被叫做用戶自定義函數(shù)2021-09-09
Python 調(diào)用有道翻譯接口實(shí)現(xiàn)翻譯
這篇文章主要介紹了Python 調(diào)用有道翻譯接口實(shí)現(xiàn)翻譯,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03

