16

I am trying to remove the default "box like" icon from the tkinter OptionMenu and replace it with my own image file. below is the code I have to date. It is working but I had to add the last line to get it to display the arrow image and for the OptionMenu to function. However, the arrow image is always imedately after the text rather than at the far right of the OptionMenu and sticky does not seam to be aplying hence the width=140. I am working in Python 2.6.

Any sugegestions for moving the image to the right?

Default What I am Getting

...
arrow = PhotoImage(file='arrow.gif')
om = OptionMenu(root,myVar,*myOptList)
om.grid(sticky=W+E,padx=5,pady=5)
om.config(indictoron=0,compound='right',image=arrow,width=140)
om.image=arrow
...
martineau
  • 119,623
  • 25
  • 170
  • 301

4 Answers4

6

You can use the ttk.Combobox widget instead:

om = Combobox(root, values=*myOptList)
om.set(myVar)
om.grid(sticky=W + E, padx=5, pady=5)
om.config(compound='right', width=140)
Peter Wood
  • 23,859
  • 5
  • 60
  • 99
  • Why not a `ttk.OptionMenu`? – martineau Jan 10 '22 at 08:19
  • @martineau I don't know enough about `OptionMenu` to recommend it. – Peter Wood Jan 10 '22 at 09:55
  • Neither had I until very recently. They're more `OptionMenu`-like than a `Combobox` in IMO. Search and ye shall find. They also have a docsting. – martineau Jan 10 '22 at 15:06
  • @martineau I answered this question almost 6 years ago, at a time I was doing a lot of Tkinter development and was having to learn and spend time just to keep up. Learning from someone who is learning is like drinking from a flowing stream, as the saying goes. Unfortunately I'm now pretty stagnant, and have no time. – Peter Wood Jan 10 '22 at 15:42
  • 1
    I understand—if nothing else my comment will make others aware of its existence. – martineau Jan 10 '22 at 16:54
  • @martineau I appreciate your commitment to getting the best answers for everyone's benefit. – Peter Wood Jan 10 '22 at 21:03
  • 2
    For anyone interested, here's a link to some good `ttk.OptionMenu` [documentation](https://www.pythontutorial.net/tkinter/tkinter-optionmenu/) I found. – martineau Jan 17 '22 at 00:15
5

You can disable the Indicator, and then use your own indicator image. Further adjust the position as it suits. Check the sample snippet below:

from Tkinter import*
import PIL
from PIL import ImageTk, Image

class MyOptionMenu(OptionMenu):
    def __init__(self, master, status, *options):
        self.var = StringVar(master)
        self.img = ImageTk.PhotoImage(Image.open("...")) #replace with your own indicator image
        self.var.set(status)
        OptionMenu.__init__(self, master, self.var, *options)
        self.config(indicatoron=0, image = self.img, font=('calibri',(10)),bg='white',width=12)
        self['menu'].config(font=('calibri',(10)),bg='white')

root = Tk()
mymenu = MyOptionMenu(root, 'Select status', 'a','b','c')
mymenu.pack()
root.mainloop()
martineau
  • 119,623
  • 25
  • 170
  • 301
HardCoder
  • 249
  • 3
  • 12
4

You can turn off the indicator, and not use the compound attribute. Create the arrow as a label with an image and no borders or text. You can then use place to place the label on the far right of the button (using the relx attribute). This is the type of thing place is really good at.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
2

That won't work and regretable i don't see an easy solution. The main problem here is, that OptionMenu is a composite widget. It's a descendant of Menubutton (which ironically is marked as deprecated/obsolte in the tkinter source) and contains a menu-widget.

Afaik the image-option you are using is packed together with the label-text and won't "detach" through your layout-configuration attempts. The more sane approach should be to influence the indicator-widget/representation which you disabled with IndicatorOn=0. But no luck there either, because i just can't figure out what the heck the indicator is...

Btw somehow it looks like an awful hack:

class OptionMenu(Menubutton): 
"""OptionMenu which allows the user to select a value from a menu.""" 
    def __init__(self, master, variable, value, *values, **kwargs):
    ...
    #'command' is the only supported keyword  <--- lol?! WTF?! why?
              callback = kwargs.get('command') 
              if kwargs.has_key('command'): 
                  del kwargs['command'] 
              if kwargs: 
                 raise TclError, 'unknown option -'+kwargs.keys()[0] # yeah sure! - unknown my a** 8-/

if you look at the source of tkinter and compare it to the original. That's also the reason why you have to add a second line after the "initialization"

om.config(indictoron=0,compound='right',image=arrow,width=140)

In the genuine source you may find, that an initial hunch about the button being some kind of a radiobutton, is not so far out of the field, but it doesn't help (at least not me) to solve the tkinter issue. :-(

I'm sorry i couldn't be of any better use.... shame on me! :( But i'll try harder the next time! ;-)

Don Question
  • 11,227
  • 5
  • 36
  • 54