这是对问题和答案的延伸 此处.
我想创建两个Comboboxes,第二个Combobox中的项目取决于第一个Combobox中的选择。此外,我希望下拉列表框的大小能够适应列表中的文本,就像答案中的那样。此处. 然而,我在这第二部分遇到了一些困难。我想用Python来解决这个问题。
我使用.pack()和.forget()代替.place()和.place_forget()得到了不同的结果,但是我还没有能够创建一个强大的解决方案。如果可能的话,使用.place比.pack或.grid更可取。
作为一个MWE,我扩展了上一个问题中的一个答案的代码。c2的下拉列表框可以正常调整大小,但是c1的下拉列表框却不能。
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()
# check if the combobox already has the "postoffest" property
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):
# no need to make the popdown smaller
return
# create an unique style name using widget's id
unique_name='Combobox{}'.format(combo.winfo_id())
# the new style must inherit from curret widget style (unless it's our custom style!)
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)
def update_c1_list(event):
c1.place_forget()
_ = c.get()
if _ == "fruit":
c1['values'] = ('apples are the best', 'bananas are way more better')
elif _ == "text":
c1['values'] = ("here's some text", "and here's some much longer text to stretch the list")
else:
pass
c1.place(x=10,y=40)
root = tk.Tk()
root.title("testing the combobox")
root.geometry('300x300+50+50')
c = ttk.Combobox(root, values=['fruit','text'], state="readonly", width=10)
c.bind('<Configure>', on_combo_configure)
c.bind('<<ComboboxSelected>>', update_c1_list)
c.place(x=10,y=10)
c1 = ttk.Combobox(root, state="readonly", width=10)
c1.bind('<Configure>', on_combo_configure)
c1.place(x=10,y=40)
c2 = ttk.Combobox(root, state="readonly", width=10)
c2.bind('<Configure>', on_combo_configure)
c2.place(x=10,y=70)
c2['values']=('this list resizes fine','because it is updated outside of the function')
root.mainloop()
欢迎任何帮助,谢谢。
在玩了一圈之后,我想出了一个函数,它可以 "在飞行中 "更新一个组合框的列表框宽度。然而,这有点像用锤子固定窗口,会引起一些问题。
def Change_combo_width_on_the_fly(combo,combo_width):
style = ttk.Style()
# check if the combobox already has the "postoffest" property
current_combo_style = combo.cget('style') or "TCombobox"
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") - (combo_width*6+23)
if (width<0):
# no need to make the popdown smaller
return
# create an unique style name using widget's id
unique_name='Combobox{}'.format(combo.winfo_id())
# the new style must inherit from curret widget style (unless it's our custom style!)
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)
作为一个MWE,代码可以按如下方式使用。
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.font as tkfont
root = tk.Tk()
c1 = ttk.Combobox(root, state="readonly", width=10)
c1.place(x=10,y=40)
Change_combo_width_on_the_fly(c1,10)
root.mainloop()
虽然这个函数可以完成任务,但它在我的代码中的其他地方造成了问题。特别是,它把之前打包的widget(滚动条)弄得一团糟。我认为它改变了最后放置的widget的样式,但我不知道如何解决这个问题。