tkinter自定义下拉多选框问题

作者:奋斗中的打工人 时间:2022-09-27 06:40:00 

使用tkinter实现下拉多选框

效果如图:

1、选择一些选项

tkinter自定义下拉多选框问题

2、全选选项

tkinter自定义下拉多选框问题

代码如下:

import tkinter

from ComBoPicker import Combopicker

list = ["全选", "选项1", "选项2", "选项3", "选项4", "选项5", "选项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) #创建框架
       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()  # 清空选项
           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)
       # 可以通过复选框的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

来源:https://blog.csdn.net/summerriver1/article/details/127420084

标签:tkinter,下拉,多选框
0
投稿

猜你喜欢

  • MySQL中SQL的单字节注入与宽字节注入

    2009-03-25 14:49:00
  • 教你用python提取txt文件中的特定信息并写入Excel

    2021-02-11 00:41:41
  • MySql 缓存查询原理与缓存监控和索引监控介绍

    2024-01-29 07:30:15
  • Sql 语句学习指南第1/2页

    2024-01-25 07:13:01
  • Python视频编辑库MoviePy的使用

    2022-12-22 21:07:07
  • keras多显卡训练方式

    2022-05-01 02:50:21
  • Linux下mysql源码安装笔记

    2024-01-19 23:45:08
  • 对python 生成拼接xml报文的示例详解

    2021-10-24 13:07:38
  • SQL Server 排序函数 ROW_NUMBER和RANK 用法总结

    2024-01-20 17:16:36
  • 十分钟轻松掌握dataframe数据选择

    2021-03-03 11:11:40
  • SQLSERVER对索引的利用及非SARG运算符认识

    2024-01-14 23:24:34
  • mysql数据表和数据表关联

    2010-12-03 16:00:00
  • Go语言实现超时的三种方法实例

    2023-06-22 18:32:43
  • Python模仿POST提交HTTP数据及使用Cookie值的方法

    2022-05-04 04:37:35
  • asp如何做一个只能从本站点才能访问的页面?

    2010-07-12 19:00:00
  • MySQL 多表关联一对多查询实现取最新一条数据的方法示例

    2024-01-22 13:58:17
  • python 实现检验33品种数据是否是正态分布

    2022-09-25 19:57:55
  • [翻译]标记语言和样式手册 chapter 6 短语元素

    2008-01-25 16:37:00
  • 微信小程序实现图片上传功能

    2023-09-06 13:08:44
  • SQL Server 2005/2008 导入导出数据常见报错解决方法

    2024-01-28 00:31:12
  • asp之家 网络编程 m.aspxhome.com