在使用 Tkinter
的 OptionMenu
小部件时,如果选项列表较多或选项内容较长,可能会导致溢出的问题(例如,选项框变得过大或超出窗口边界)。以下是常见的溢出问题及解决方法:
1、问题背景
当在 Windows 系统下使用 Python 2.7 创建 Tkinter 应用程序时,OptionMenu 的右上角(单击时会显示选项的下拉按钮)被截断在中间。以下代码可以重现此问题:
from Tkinter import Tk, StringVar
from ttk import OptionMenu
root = Tk()
options = list('ABC')
var = StringVar(value='A')
om = OptionMenu(root, var, var.get(), *options)
om.configure(width=25)
om.pack()
root.mainloop()
问题现象如下图所示:
经过尝试,修改填充布局管理器的 padx 和 ipadx 关键字以及使用网格布局均无法完全显示下拉箭头。
2、解决方案
对于该问题,有以下解决方案:
- 更新 Tcl/Tk 版本
根据 bug 报告,此问题在 Tk 8.5.8 中已修复。更新 Python 中的 Tcl/Tk 可以解决此问题,但更新过程可能比较复杂。
- 修改 vistaTheme.tcl 脚本文件
也可以修改 Tk 库中包含的脚本文件 vistaTheme.tcl 来解决此问题。在 Python 中使用以下代码获取 Tk 库的路径:
from Tkinter import Tk
tk = Tk()
tk.eval("set tk_library")
然后,编辑 /ttk/vistaTheme.tcl 文件,并将内容修改为以下内容:
#vistaTheme.tcl
#
#Vista Theme for Tk 8.5 and above
proc vistaTheme::Style { style }= {
if {$style == "palette"} {
set map {
activeBackground #ffffff
activeForeground #000000
background #ffffff
disabledBackground #f0f0f0
disabledForeground #808080
foreground #000000
highlightBackground #4682b4
highlightColor #4682b4
highlightThickness 1
inactiveBackground #ffffff
inactiveForeground #505050
selectBackground #d9d9f3
selectForeground #000000
}
set bar map {
troughcolor #ffffff
thumbcolor #d9d9f3
troughrelief flat
}
set pens map {
background #ffffff
foreground #000000
disabledforeground #808080
disabledbackground #f0f0f0
selectbackground #d9d9f3
activebackground #4682b4
activeforeground #ffffff
}
set menu map {
background #ffffff
disabledforeground #808080
disabledbackground #d9d9d9
foreground #000000
activebackground #4682b4
activeforeground #ffffff
}
set scrollbar map {
troughcolor #ffffff
troughrelief flat
background #d9d9f3
thumbcolor #666666
arrowcolor #666666
bordercolor #666666
relief flat
}
set progressbar map {
troughcolor #ffffff
troughrelief flat
background #d9d9f3
barcolor #4682b4
bordercolor #4682b4
relief flat
}
return
}
vistaTheme::Style palette
set scheme [tk::Priv::VistaStyle theme]
set info [tk::Priv::VistaStyle GetWindowTheme info]
set disabledFg [string map [list $info(APPEARANCE_DISABLED) $map(disabledForeground)]]
set foreground [string map [list $info(APPEARANCE_ACTIVE) $map(foreground)]]
set widgetClass [tk class [winfo class [$scheme(HWND)]]]
if { $scheme(THEME_NAME) == "aero" && $widgetClass != "" } {
switch -glob -- $widgetClass {
"Scrollbar*"*
{
if { $scheme(THEME_PART) == "SCROLLBAR_THUMB" } {
set disabledFg [string map [list $info(APPEARANCE_DISABLED) $pens(activeforeground)]]
set foreground [string map [list $info(APPEARANCE_ACTIVE) $pens(activeforeground)]]
}
}
"ComboBox*Entry"
{
if {$scheme(THEME_PART) == "COMBOBOX_DROPDOWNBUTTON"} {
set foreground [string map [list $info(APPEARANCE_DISABLED) $pens(activeforeground)]]
set disabledFg [string map [list $info(APPEARANCE_DISABLED) $pens(disabledforeground)]]
} else {
set disabledFg [string map [list $info(APPEARANCE_DISABLED) $pens(disabledforeground)]]
set foreground [string map [list $info(APPEARANCE_ACTIVE) $pens(background)]]
}
}
"ListView*Header"
{
set disabledFg [string map [list $info(APPEARANCE_DISABLED) $pens(activeforeground)]]
}
"ListView*Item"
{
set disabledFg [string map [list $info(APPEARANCE_DISABLED) $pens(disabledforeground)]]
}
"TreeView*Header"
{
set disabledFg [string map [list $info(APPEARANCE_DISABLED) $pens(activeforeground)]]
}
"TreeView*Item"
{
set disabledFg [string map [list $info(APPEARANCE_DISABLED) $pens(disabledforeground)]]
}
}
}
foreach name [ lsort $map ] {
set value [string map [list $info(APPEARANCE_ACTIVE) $disabledFg [list $info(APPEARANCE_DISABLED) $map($name)]]]
if { $value != $map($name) } {
$style configure -{} -$name $value
}
}
foreach name [ lsort $bar ] {
set value [string map [list $info(APPEARANCE_ACTIVE) [list $info(APPEARANCE_DISABLED) $bar($name)]]]
if { $value != $bar($name) } {
$style configure -{} -$name $value
}
}
foreach name [ lsort $pens ] {
set value [string map [list $info(APPEARANCE_ACTIVE) [list $info(APPEARANCE_DISABLED) $pens($name)]]]
if { $value != $pens($name) } {
$style configure -{} -$name $value
}
}
foreach name [ lsort $menu ] {
set value [string map [list $info(APPEARANCE_ACTIVE) [list $info(APPEARANCE_DISABLED) $menu($name)]]]
if { $value != $menu($name) } {
$style configure -{} -$name $value
}
}
foreach name [ lsort $scrollbar ] {
set value [string map [list $info(APPEARANCE_ACTIVE) [list $info(APPEARANCE_DISABLED) $scrollbar($name)]]]
if { $value != $scrollbar($name) } {
$style configure -{} -$name $value
}
}
foreach name [ lsort $progressbar ] {
set value [string map [list $info(APPEARANCE_ACTIVE) [list $info(APPEARANCE_DISABLED) $progressbar($name)]]]
if { $value != $progressbar($name) } {
$style configure -{} -$name $value
}
}
}
修改后,OptionMenu 的下拉箭头就可以完全显示了。