通过深入解读patthoyts给出的优秀答案,我们可以得到一个使用派生样式而不是修改 TCombobox
样式的通用解决方案(但请注意Tk的一个错误,稍后会有更多信息)。
基本上,为每个组合框创建一个具有唯一名称的新样式(我不知道这如何扩展 - 或许只在需要时应用更安全)。此外,从组件本身中读取组合框值,并取最长的值:还有一个检查来避免使下拉框小于窗口部件,如果插入短文本。
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.font as tkfont
def on_combo_configure(event):
combo = event.widget
style = ttk.Style()
current_combo_style = combo.cget('style') or "TCombobox"
if len(style.lookup(current_combo_style, 'postoffset'))>0:
return
combo_values = combo.cget('values')
if len(combo_values) == 0:
return
longest_value = max(combo_values, key=len)
font = tkfont.nametofont(str(combo.cget('font')))
width = font.measure(longest_value + "0") - event.width
if (width<0):
return
unique_name='Combobox{}'.format(combo.winfo_id())
if unique_name in current_combo_style:
style_name = current_combo_style
else:
style_name = "{}.{}".format(unique_name, current_combo_style)
style.configure(style_name, postoffset=(0,0,width,0))
combo.configure(style=style_name)
root = tk.Tk()
root.title("testing the combobox")
root.geometry('300x300+50+50')
fruit = ['apples are the best', 'bananas are way more better']
c = ttk.Combobox(root, values=fruit, width=10)
c.bind('<Configure>', on_combo_configure)
c.pack()
c1 = ttk.Combobox(root, values=['shorter','than','widget'], width=15)
c1.bind('<Configure>', on_combo_configure)
c1.pack()
root.mainloop()
但是...
正如之前所述,Tk Combobox中存在一个bug:从派生样式中只读取TCombobox
样式的postoffset
属性。
可以通过编辑[python-install-dir]\tcl\tk[version]\ttk\combobox.tcl
来解决这个问题;在PlacePopdown方法中找到以下行:
set postoffset [ttk::style lookup TCombobox -postoffset {} {0 0 0 0}]
并将其替换为:
set style [$cb cget -style]
set postoffset [ttk::style lookup $style -postoffset {} {0 0 0 0}]
或者,等待我的拉取请求被合并并发布。
width = max(0,font.measure(long.strip() + '0') - combo.winfo_reqwidth())
缩短函数,这意味着您可以省略if
语句。此外,函数末尾的combo.configure(style='TCombobox')
行仍然是必需的。 - Thomas Kühncombo.winfo_reqwidth()
更改为combo.winfo_width()
。我注意到如果我最大化窗口并且组合框的宽度发生变化,它会给它比它需要的更多。更新了我的答案以反映这个改变和 Thomas 的建议 :). - MickeyPvX