1

Now I understand that there is already a similar question Python Tkinter: OptionMenu modify dropdown list width however this does not help me.

I am trying to make the width of the drop down menu from the OptionMenu widget responsive. Meaning that the width will always match the width of the OptionMenu. As shown in the code below, I've tried a few things but they don't apply to the submenu and it will always stay at a fixed width. Is there no way to change it?

import tkinter as tk

root = tk.Tk()

var = tk.StringVar()
var.set('First')

option = tk.OptionMenu(root, var, 'First', 'Second', 'Third')
option.configure(indicatoron = False)

option.pack(expand = True, fill = tk.X)

# Sub-menu config
submenu = option['menu']
submenu.configure(width = 50) # Can't use width
submenu.pack_configure(expand = True, fill = tk.X) # Can't use pack_configure

root.mainloop()
Community
  • 1
  • 1
Steven Summers
  • 5,079
  • 2
  • 20
  • 31
  • This is a complete duplicate of the other question you refer to. I've given an answer there. This one should be closed, but SO won't allow it because the other question doesn't have an up-voted or accepted answer. – Bryan Oakley Oct 27 '15 at 12:24
  • Thank you. I never really considered using ttk. I just kinda stuck with tkinter. Should I delete question if it can't be closed? – Steven Summers Oct 27 '15 at 15:46

1 Answers1

2

while there is no way to explicitly set the width, if you really must use tkinter then it is possible to add hacky workarounds to pad these things out. and example of this would be:

import tkinter as tk
from tkinter import font as tkFont

def resizer(event=None):
    print("Resize")
    widget = event.widget
    menu = widget['menu']

    req_width = widget.winfo_width()-10
    menu_width = menu.winfo_reqwidth()

    cur_label = menu.entrycget(0, "label")
    cur_label = cur_label.rstrip() # strip off existing whitespace

    font = tkFont.Font() # set font size/family here
    resized = False
    while not resized:
        difsize = req_width - menu_width # check how much we need to add in pixels
        tempsize = 0
        tempstr = ""
        while  tempsize < difsize:
            tempstr += " " # add spaces into a string one by one
            tempsize = font.measure(tempstr) #measure until big enough
        menu.entryconfigure(0, label=cur_label + tempstr) # reconfigure label
        widget.update_idletasks() # we have to update to get the new size
        menu_width = menu.winfo_reqwidth() # check if big enough
        cur_label = menu.entrycget(0, "label") # get the current label for if loop needs to repeat
        if menu_width >= req_width: # exit loop if big enough
            resized = True

root = tk.Tk()

var = tk.StringVar()
var.set('First')

option = tk.OptionMenu(root, var, 'First', 'Second', 'Third')
option.bind("<Configure>", resizer) # every time the button is resized then resize the menu
option.configure(indicatoron = False)

option.pack(expand = True, fill = tk.X)

root.mainloop()

this essentially just pads out the first menu item until the menu is big enough. however there does seem to be some discrepancy in the widths reported back by tkinter hence my req_width = widget.winfo_width()-10 offset near the top.

however this will not always be a perfect match size wise, while testing my a space seems to take 3 pixels of width, so it could be 1 or 2 pixels out at any time.

James Kent
  • 5,763
  • 26
  • 50
  • Wow, that's impressive. Thank you for your response, but I think I might just switch over to ttk instead. I never really took much notice of ttk until now and so I'm going to use it to improve my GUI. Thanks very much though. – Steven Summers Oct 28 '15 at 02:03
  • no problem, tbh that is what i would recommend, as soon as you start using hacky workarounds like this you end up with weird bugs that can be hard to resolve and it also becomes more resource heavy to run. and personally i find that ttk widgets look more natural on most platforms than the tkinter ones – James Kent Oct 28 '15 at 08:50