Python tkinter多选下拉列表框,支持全选、取消全选、反选

说明

1、参考大佬写的博文:Python tkinter自定义多选下拉列表框,根据自己的需要加了一些功能,在这里分享一下

2、内容概况:

  1. 自定义输入框,我这里改成了ScrolledText标签
  2. 加了滚动条x,y
  3. 选项根据自身文本长度展示,解决文本过长部分选项展示不全的问题
  4. 加了全选按钮功能
  5. 加了取消全选按钮功能
  6. 加了反选按钮功能
    在这里插入图片描述

自定义输入框的修改方法

  1. 继承标签类
    我这里已ScrolledText标签为例
    在这里插入图片描述

  2. 替换102行的标签名,对应的实例也需要替换
    在这里插入图片描述

3、全选、取消全选、反选

在这里插入图片描述

全部代码内容如下:

# _*_ coding:utf8 _*_

import tkinter as tk
from tkinter import ttk
from tkinter.scrolledtext import ScrolledText

class Picker(tk.Frame):

    def __init__(self, master, values, entry_wid, command):
        self._selected_item = None
        self._values = values
        self._entry_wid = entry_wid
        self._command = command
        ttk.Frame.__init__(self,
                           master,
                           borderwidth=1,
                           relief="solid")

        canvas = tk.Canvas(self)
        self.frame_ = tk.Frame(canvas)
        # 设置滚动条
        sb_y = tk.Scrollbar(self, orient="vertical", command=canvas.yview)
        sb_x = tk.Scrollbar(self, orient="horizontal", command=canvas.xview)
        canvas.configure(yscrollcommand=sb_y.set)
        canvas.configure(xscrollcommand=sb_x.set)
        sb_y.pack(side="right", fill="y")
        sb_x.pack(side="bottom", fill="x")

        canvas.pack(side="left")
        canvas.create_window((0, 0), window=self.frame_, anchor='nw')

        # 绑定鼠标滚动
        def canvas_scroll(event):
            if event.delta == -120:
                canvas.yview_scroll(1, "units")
            elif event.delta == 120:
                canvas.yview_scroll(-1, "units")
            else:
                canvas.yview_scroll(-1 * (event.delta / 120), "units")

        self.bind("<MouseWheel>", canvas_scroll)

        self.frame_.bind("<Configure>", lambda event: canvas.configure(scrollregion=canvas.bbox("all"), width=400, height=300))

        # 绑定焦点事件
        self.bind("<FocusIn>", lambda event: self.event_generate('<<PickerFocusIn>>'))
        self.bind("<FocusOut>", lambda event: self.event_generate('<<PickerFocusOut>>'))


        # 生成选项
        self.dict_checkbutton = {}
        self.dict_intvar_item = {}
        for index,item in enumerate(self._values):
            self.dict_intvar_item[item] = tk.IntVar()
            self.dict_checkbutton[item] = ttk.Checkbutton(self.frame_,
                                                          text=item,
                                                          variable=self.dict_intvar_item[item],
                                                          width=len(item) + self.str_count(item) * 1.5,
                                                          command=lambda ITEM=item: self._command(ITEM, 2))
            self.dict_checkbutton[item].grid(row=index, column=0, sticky=tk.NSEW)
            self.dict_intvar_item[item].set(0)

        # 全选按钮
        tk.Button(self.frame_, text='全选', command=lambda select_type=1: self.select_all(select_type)).grid(row=0, column=1, sticky=tk.NSEW)
        # 全部取消
        tk.Button(self.frame_, text='取消', command=lambda select_type=0: self.select_all(select_type)).grid(row=1, column=1, sticky=tk.NSEW)
        # 反选
        tk.Button(self.frame_, text='反选', command=lambda select_type=2: self.select_all(select_type)).grid(row=2, column=1, sticky=tk.NSEW)

    def select_all(self, select_type=None):
        for index, item in enumerate(self._values):
            if select_type == 2 and self.dict_intvar_item[item].get() == 0:
                self.dict_intvar_item[item].set(1)
            elif select_type == 2 and self.dict_intvar_item[item].get() == 1:
                self.dict_intvar_item[item].set(0)
            else:
                self.dict_intvar_item[item].set(select_type)

            self._command(item, self.dict_intvar_item[item].get())

    def str_count(self, str):
        """统计宽字符的数量,因为中文和数字占用宽度不一样"""
        zh_cn = 0
        for s in str:
            if s.isalpha():
                zh_cn += 1
        return zh_cn


class Combopicker(Picker, ScrolledText):

    def __init__(self, master, values: list):
        self.entry_var = tk.StringVar()

        # 配置下拉选项和输入框的样式
        entry_config = {
            "width": 60,
            "height": 30,
            "wrap": tk.WORD
        }

        self.st = ScrolledText
        self.st.__init__(self, master, **entry_config)

        self._is_menuoptions_visible = False
        # 初始化参数
        self.picker_frame = Picker(self.winfo_toplevel(),
                                   values=values,
                                   entry_wid=self.entry_var,
                                   command=self._on_selected_check)

        self.bind_all("<1>", self._on_click, "+")

        self.bind("<Escape>", lambda event: self.hide_picker())


        # 是否有选择历史审批流程
        self.his_sp = False


    def get_e_value(self):
        if not self.his_sp:
            return
        # 删除已输入内容
        self.st.delete(self, '1.0', 'end')
        if self.entry_var.get() == '':
            return
        # 输入到文本框中
        self.st.insert(self, '1.0', self.entry_var.get())

    def _on_selected_check(self, SELECTED, it_):
        self.his_sp = True
        # 勾选
        value = []
        if self.entry_var.get() != "" and self.entry_var.get() != None:
            # 获取字符串动态变量的内容
            temp_value = self.entry_var.get()
            value = temp_value.split("\n")

        # 取消勾选
        if str(SELECTED) in value and it_ == 0:
            value.remove(str(SELECTED))
        elif str(SELECTED) in value and it_ == 2:
            value.remove(str(SELECTED))
        elif str(SELECTED) not in value and it_ == 2:
            value.append(str(SELECTED))
        elif str(SELECTED) not in value and it_ == 1:
            value.append(str(SELECTED))
        else:
            pass

        value.sort()

        # 把值赋值给输入框的变量,
        temp_value = ""
        for index, item in enumerate(value):
            if item != "":
                if index != 0:
                    temp_value += "\n"
                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()
                self.get_e_value()
                self.his_sp = False

    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 = True

    def hide_picker(self):
        # 隐藏下拉选项
        if self._is_menuoptions_visible:
            self.picker_frame.place_forget()
        self._is_menuoptions_visible = False


if __name__ == "__main__":
    root = tk.Tk()
    root.geometry("500x800+100+150")
    root.attributes('-topmost', 'true')

    v_ = ['CELL-S1',
        'CELL-S2',
        'CELL-S2',
        'CELL-S2',
        'CELL-S2',
        'CELL-S2',
        'CELL-S2',
        'CELL-S2',
        'CELL-S2',
        'CELL-S31222222222222222222222221aaav',
        'CELL-S334332',
        'CELL-S3呀呀呀呀呀呀晕晕晕q',
        'CELL-S3ccccccccccccccccccccccccccc',
        'CELL-S3发的哒哒哒哒哒哒多多多f',
        'CELL-S3',
        'CELL-S3',
        'CELL-S3 个梵蒂冈地方个地方s',
        'CELL-S3水电费d',
        'CELL-S4']
    v = ['{:0>2}  {}'.format(i+1, v_[i]) for i in range(len(v_))]

    cp = Combopicker(root, values=v)
    cp.pack(anchor="w")

    root.mainloop()


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值