Tkinter OptionMenu:通过列表中最长的菜单项设置宽度

6
Tkinter的OptionMenu根据当前活动的菜单项设置其宽度。我正在寻找一种方法,使其基于最宽的菜单项而不是当前选择的菜单项来设置其宽度,以防止用户选择不同的菜单项时小部件重新调整大小。
问题Tkinter Option Menu Widget Changing Widths中提供的建议答案隐藏了问题,但并未解决它。(提示:不是重复!) 接受的答案是将小部件设置为同时粘附到WE。 只要列的建议大小大于框中所有项目的宽度,这就隐藏了问题,但实际上并没有解决问题。
我有一个(也更喜欢)使用各种小部件的grid布局列,其大小基于小部件的宽度动态调整。但是,如果用户选择比其他任何项都宽的项目,则希望OptionMenu小部件报告的宽度为最宽项的宽度,而不是当前选择的项的宽度,因为整个列的宽度会发生变化。
到目前为止,我找到的所有建议方法都是将小部件 WE 粘在一起,这本身并不能解决我的问题,在设置与项目长度无关的任意常数宽度方面也不是我想要的。
3个回答

7
感谢留下答案的两位,但使用等宽字体或将宽度设置为字符串长度都不是理想解决方案。后者太不准确了,因为宽度参数接受一个数字,这个数字是特定字体中字符“0”的宽度对应的“文本单位”。所以我的最终解决方案如下:
  1. 找出元素使用的字体。
  2. 使用measure查找每个字符串的宽度。(这里给出的是像素值)
  3. 将最长的宽度除以字符“0”的宽度。现在你有了“文本单位”中的宽度。
这给出了以下代码。可能可以更Pythonic并且是OptionMenu等的子类方法,但它有效。
def setMaxWidth(stringList, element):
    f = tkFont.nametofont(element.cget("font"))
    zerowidth=f.measure("0")
    w=max([f.measure(i) for i in stringList])/zerowidth

    element.config(width=w)

出于好奇,我想知道我的数据中每个字符串的调整宽度与字符长度有何不同。这是一个简单的循环来完成这个任务,并提供了我的字符串的经验数据。

    for i in stringList:
        print len(i), float(f.measure(i))/float(zerowidth)

数据如下:
4 3.83333333333
24 20.1666666667
22 18.5
11 11.1666666667
12 11.3333333333
14 12.6666666667

左列为字符串长度,右列为计算所得的宽度。换句话说,简单地使用 len(max(opts, key=len)) 会在所有情况下给出比实际需要更大的部件大小。(当然这是可以预料的。)我还比较了使用重复的字符 W 和重复的字符 . 进行特殊测试时小部件的计算宽度,在所有情况下,这些人工测试字符串测试都与小部件请求的宽度“通常”一致,而且没有手动设置宽度。


一个稍微简单的解决方案是将选项菜单放在一个框架中,然后以像素为单位设置框架的大小。这样可以省去一些计算,但需要增加一个小部件。 - Bryan Oakley
@BryanOakley 我可以为每个 OptionMenu 添加一个额外的小部件,但这似乎比这更复杂,甚至更加 hackier/uglier。尽管需要进行额外的数学计算,但这似乎更像“设置并忘记”。 - nitro2k01
在Python 3中,tkFont被重命名为font,您需要将结果浮点数转换为Int,但除此之外,它的工作方式非常好。 - Svavelsyra

2

如果你的GUI使用的是等宽字体,你可以获取OptionMenu中填充列表中最长元素的长度,并基于此设置宽度。

from Tkinter import *

root = Tk()

opts = ['bacon', 'cereal', 'eggs']

oMenuWidth = len(max(opts, key=len))

v = StringVar(root)
v.set(opts[0])
oMenu = OptionMenu(root, v, *opts)
oMenu.config(width=oMenuWidth)
oMenu.grid()

mainloop()

我想即使它不是固定长度,你也可以在实施之前对宽度进行数学运算,以使其接近正确。


1
这是你的两个选择:设置固定宽度或者依赖单元格宽度来控制小部件的宽度。设置一个非随意的固定宽度应该很容易,因为你是设置小部件内容的人。只需跟踪放入小部件中的最宽项目,并使用该宽度作为小部件的期望宽度即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接