探究Tkinter ttk组件结构与事件,优化多选ComboBox实现
深入了解ttk.Combobox的组件结构与事件
我想用Python的tkinter.ttk实现一个多选ComboBox,已经写出了可用的代码,但希望能更精准地控制ttk.Combobox。我已经知道怎么查看ttk组件的样式和布局,现在需要了解它的事件体系和组件结构。
我的实现代码如下:
import tkinter as tk from tkinter import ttk class MultiBox(ttk.Combobox): def __init__(self,window,**kwds): self._separator = kwds.pop('separator',None) self._joinChar = self._separator if self._separator is not None else ' ' kwds["textvariable"] = self._v = kwds.pop('textvariable',tk.StringVar()) self._v.trace('w',self.vwrite) self.onchange = kwds.pop('onchange',None) super().__init__(window,**kwds) self["values"] = self._values = list(kwds.pop('values',())) self._cv = '' def vwrite(self,*args): v = set((_ for _ in self._v.get().split(self._separator) if _ in self._values)) cv = set((_ for _ in self._cv.split(self._separator) if _ in self._values)) lv = v if v&cv else v.union(cv) self._cv = self._joinChar.join(self._vsort(lv)) self._v.set(self._cv) #print(f'{v=} {cv=} {lv=} --> {self._v}') self["values"] = self._vsort((_ for _ in self._values if _ not in lv)) if self.onchange: self.onchange() def _vsort(self,L): return [_[1] for _ in sorted((self._values.index(_),_) for _ in L)] @property def value(self): return self._v.get() if __name__=='__main__': # 创建tkinter窗口 window = tk.Tk() window.geometry('350x270') # 标签 ttk.Label(window, text = "选择月份 :", font = ("Times New Roman", 10)).grid(column = 0, row = 0, padx = 10, pady = 25) mb0 = MultiBox(window, width = 20, values=('January','February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'), ) mb0.grid(column = 1, row = 0) # 默认选中第2项 mb0.current(1) mb1 = MultiBox(window,width=20,values='A a,B b,C c,D d,E e,F f'.split(','),separator=',') mb1.grid(column = 1, row = 5, pady=10) mb1.current(0) b0 = ttk.Button(window, text="打印选中值", command=lambda :print(f'mb0.value={mb0.value} mb1.value={mb1.value}')).grid(column=1, row=15, pady=5) b1 = ttk.Button(window, text="退出", command=window.destroy).grid(column=1, row=20, pady=5) #from ttkstyopt import ttkStyOpt #window.after(10000, lambda : ttkStyOpt(multibox)) window.mainloop()
一、ttk.Combobox的组件结构
ttk.Combobox是复合组件,由多个基础ttk组件组合而成,核心组成部分包括:
- Entry输入框:用户直接查看或输入内容的区域,负责显示已选中的文本。
- 下拉箭头按钮:点击后触发下拉列表的展开/收起操作。
- 动态下拉列表:展开后显示可选值的列表,它是临时生成的顶级窗口(Toplevel),并非Combobox的直接子组件,仅在触发下拉时创建。
你可以通过以下代码查看Combobox的布局层级细节:
style = ttk.Style() print(style.layout('TCombobox'))
输出会展示布局中各元素的层级关系,比如Entry.field(输入框区域)、Arrow.button(下拉按钮)等。
二、ttk.Combobox的核心事件
以下是对自定义多选ComboBox有用的关键事件,可通过bind()方法绑定来增强控制:
1. 下拉列表选择事件
<<ComboboxSelected>>:用户从下拉列表选中选项时触发,这是处理选择逻辑最精准的事件,比文本变量追踪更适合捕捉用户的主动选择操作。
2. 交互状态事件
<Button-1>:绑定到下拉按钮时,可自定义下拉列表的展开逻辑,比如展开前同步已选中选项的状态。<Map>:下拉列表展开(显示)时触发。<Unmap>:下拉列表收起(隐藏)时触发。
3. 文本输入相关事件
<KeyRelease>:用户在输入框释放按键时触发,适合处理自定义文本过滤或多选文本解析。<FocusOut>:Combobox失去焦点时触发,可用来验证输入内容,确保仅保留合法选项。
事件绑定示例
给MultiBox添加<<ComboboxSelected>>绑定,优化选择逻辑:
class MultiBox(ttk.Combobox): def __init__(self,window,**kwds): # ... 原有初始化代码 ... self.bind('<<ComboboxSelected>>', self.on_select) def on_select(self, event): selected = self.get() current_selected = set(self._cv.split(self._separator)) current_selected.add(selected) self._cv = self._joinChar.join(self._vsort(current_selected)) self._v.set(self._cv) self["values"] = self._vsort([v for v in self._values if v not in current_selected]) if self.onchange: self.onchange()
内容的提问来源于stack exchange,提问作者Robin Becker
相关产品推荐
相关产品推荐

