Tkinter - Optionmenu - 是否可以在用户单击下拉框时更改指示器箭头?

Tkinter - Optionmenu - Is it possible to change the indicator arrow when the dropdown box is clicked by the user?

我已经通过使用 indicatoron=0, compound=RIGHT, image=dropImg, width=120 设法更改了选项菜单框中的指示器,但我现在正尝试将箭头更改为在单击该框并显示元素列表时指向上方。 例如: 我试过 activeindicatoron = 0 但这不起作用。有没有人知道这在 tkinter 中是否可行?

谢谢,雅各布

是的,这是可能的。例如,您可以

  1. 使用选项菜单的 postcommand 选项将按钮上的图像更改为向上的箭头。

  2. 使用绑定到选项菜单菜单的 <Unmap> 事件,当菜单消失时恢复为向下箭头。

这是一个例子:

import tkinter as tk
root = tk.Tk()

# up and down images
down =b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x0e\x00\x00\x00\x07\x08\x06\x00\x00\x008G|\x19\x00\x00\x00\tpHYs\x00\x00\x10\x9b\x00\x00\x10\x9b\x01t\x89\x9cK\x00\x00\x00\x19tEXtSoftware\x00www.inkscape.org\x9b\xee<\x1a\x00\x00\x00OIDAT\x18\x95\x95\xce\xb1\x0e@P\x0cF\xe1\xefzI\x8fc$\x12\x111\x19\xec\x9e\x12\xcb\x95 A\x9d\xa4K\xff\x9e\xb6\t\x13J\xffX \xa1\xc7\x16\xac\x19\xc5\xb1!*\x8fy\xf6BB\xf7"\r_\xff77a\xcd\xbd\x10\xedI\xaa\xa3\xd2\xf9r\xf5\x14\xee^N&\x14\xab\xef\xa9\'\x00\x00\x00\x00IEND\xaeB`\x82'
up = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x0e\x00\x00\x00\x07\x08\x06\x00\x00\x008G|\x19\x00\x00\x00\tpHYs\x00\x00\x10\x9b\x00\x00\x10\x9b\x01t\x89\x9cK\x00\x00\x00\x19tEXtSoftware\x00www.inkscape.org\x9b\xee<\x1a\x00\x00\x00\IDAT\x18\x95\x8d\xd0A\n\x830\x14\x06\xe1/z,\x0f\xd2#\x19\\xb4\x08Ep\xe1\xbe\xd7\xe8\xc5\xd2n\x12\x11%\x92\x81\xd9<\xfe\xd9\xbc^\x9d\x88\x01\xdf\x9b\xcd\x85\t?$\x8c\xadQ\xccQ1\xe5[\x95\x80\xe7)::\xd7\xa2\xd7MT|\xe7\xed\x1e-\rQqC\x17\xb0\xe2\xd1\xfa\x80\xcc\xe7\x0fO\xbe&\x9dv\xae\xef\x97\x00\x00\x00\x00IEND\xaeB`\x82'
imgDown = tk.PhotoImage(master=root, data=down)
imgUp = tk.PhotoImage(master=root, data=up)

# create option menu
var = tk.StringVar(root, 'a')
option = tk.OptionMenu(root, var, *list('abcde'))
option.configure(indicatoron=0, compound=tk.RIGHT, image=imgDown, width=120)

# configure menu
menu = option['menu']
menu.configure(postcommand=lambda: option.configure(image=imgUp))
menu.bind('<Unmap>', lambda ev: option.configure(image=imgDown))
option.pack()

root.mainloop()

TTK版本

也可以在使用 ttk.OptionMenu 时实现这一点,我认为它看起来更好,因为箭头实际上取代了指示器而不是在图像的位置。这可以通过修改 TMenubutton 样式的布局来完成:

  1. 从图像创建 'up' 和 'down' 元素

    style.element_create('up', 'image', imgUp)
    style.element_create('down', 'image', imgDown)
    
  2. 通过将 'Menubutton.indicator' 替换为 [=] 从 'TMenubutton' 布局(使用 style.layout('TMenubutton') 获得)创建 'up.TMenubutton' 和 'down.TMenubutton' 布局56=] 或 'down'.

  3. 使用 postcommand<Unmap> 更改菜单按钮的样式。

代码如下:

import tkinter as tk
from tkinter import ttk
root = tk.Tk()

# images
down = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x0e\x00\x00\x00\x07\x08\x06\x00\x00\x008G|\x19\x00\x00\x00\tpHYs\x00\x00\x10\x9b\x00\x00\x10\x9b\x01t\x89\x9cK\x00\x00\x00\x19tEXtSoftware\x00www.inkscape.org\x9b\xee<\x1a\x00\x00\x00OIDAT\x18\x95\x95\xce\xb1\x0e@P\x0cF\xe1\xefzI\x8fc$\x12\x111\x19\xec\x9e\x12\xcb\x95 A\x9d\xa4K\xff\x9e\xb6\t\x13J\xffX \xa1\xc7\x16\xac\x19\xc5\xb1!*\x8fy\xf6BB\xf7"\r_\xff77a\xcd\xbd\x10\xedI\xaa\xa3\xd2\xf9r\xf5\x14\xee^N&\x14\xab\xef\xa9\'\x00\x00\x00\x00IEND\xaeB`\x82'
up = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x0e\x00\x00\x00\x07\x08\x06\x00\x00\x008G|\x19\x00\x00\x00\tpHYs\x00\x00\x10\x9b\x00\x00\x10\x9b\x01t\x89\x9cK\x00\x00\x00\x19tEXtSoftware\x00www.inkscape.org\x9b\xee<\x1a\x00\x00\x00\IDAT\x18\x95\x8d\xd0A\n\x830\x14\x06\xe1/z,\x0f\xd2#\x19\\xb4\x08Ep\xe1\xbe\xd7\xe8\xc5\xd2n\x12\x11%\x92\x81\xd9<\xfe\xd9\xbc^\x9d\x88\x01\xdf\x9b\xcd\x85\t?$\x8c\xadQ\xccQ1\xe5[\x95\x80\xe7)::\xd7\xa2\xd7MT|\xe7\xed\x1e-\rQqC\x17\xb0\xe2\xd1\xfa\x80\xcc\xe7\x0fO\xbe&\x9dv\xae\xef\x97\x00\x00\x00\x00IEND\xaeB`\x82'
imgDown = tk.PhotoImage(master=root, data=down)
imgUp = tk.PhotoImage(master=root, data=up)

# style
style = ttk.Style(root)
style.theme_use('clam')
style.element_create('up', 'image', imgUp)
style.element_create('down', 'image', imgDown)

style.layout('up.TMenubutton', [('Menubutton.border',
  {'sticky': 'nswe',
   'children': [('Menubutton.focus',
     {'sticky': 'nswe',
      'children': [('Menubutton.up', {'side': 'right', 'sticky': ''}),  # replace the indicator by up arrow
       ('Menubutton.padding',
        {'expand': '1',
         'sticky': 'we',
         'children': [('Menubutton.label',
           {'side': 'left', 'sticky': ''})]})]})]})])

style.layout('down.TMenubutton', [('Menubutton.border',
  {'sticky': 'nswe',
   'children': [('Menubutton.focus',
     {'sticky': 'nswe',
      'children': [('Menubutton.down', {'side': 'right', 'sticky': ''}),  # replace the indicator by down arrow
       ('Menubutton.padding',
        {'expand': '1',
         'sticky': 'we',
         'children': [('Menubutton.label',
           {'side': 'left', 'sticky': ''})]})]})]})])

var = tk.StringVar(root, 'a')
option = ttk.OptionMenu(root, var, *list('abcde'))
option.configure(style='down.TMenubutton')
menu = option['menu']
menu.configure(postcommand=lambda: option.configure(style='up.TMenubutton'))
menu.bind('<Unmap>', lambda ev: option.configure(style='down.TMenubutton'))
option.pack()

root.mainloop()