0

So I'm grabbing links of events off a website and putting them into a drop down menu to be selected. My code for the menu:

import Tkinter as tk     
from Tkinter import StringVar

selectMenu = tk.Tk()


# #-> this is what I have
# Followed by what you can use


#var = Vars()
#events = var.GetVars('Event')
events = " "
options = []
links = []
#forms = (driver.find_elements_by_class_name("with-cats")) #This is what I have
forms = ["Yolo ","Dad? Closed","Anotha One","Normies! Closed"] #This is so you can try it for yourself

for x in forms:
    #info = x.text
    info = x #Again, this is so you can try it for yourself
    if events in info.lower():
        links.append(x)

for link in range(0,len(links)):
    #options.append(links[link].text)
    options.append(links[link])
list(set(options))

selection = []
for link in range(0,len(options)):
    selection.append(options[link])
select = StringVar(selectMenu)
select.set("--None Selected--")

menu = tk.OptionMenu(selectMenu, select, *(selection))

msg = "Which one would you like to attend?"
label = tk.Label(selectMenu, text=msg, font="Helvedica 14")

label.pack(side='top', pady=10)
menu.pack(side="top", pady=10)     

selectMenu.attributes('-topmost', True)
selectMenu.mainloop()   

So this works fine and dandy, but I would like to improve the look to make it more obvious which events are open. To clarify, an event found that is open and put into the menu may look like "This is a cool event", but one that is closed would be read as "This is a cool event Closed". My aim is to be able to make the foreground red of either just the word Closed or the string containing Closed, whichever is possible if any (And I'm not sure if it's possible because menus and buttons on osx are usually defaulted to system settings, maybe there is a way around this?).

           Current:                        Desired:

Jake
  • 999
  • 1
  • 7
  • 16
  • Please provide [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). This will allow us to assist you with you question. There is not enough of your code to reproduce the problem. Without the MCVE it will be less likely that you get the answer you are looking for. – Mike - SMT Jul 24 '17 at 19:16
  • I'm sorry, I'm confused by this, what problem is trying to be produced? Can you please clarify? – Jake Jul 24 '17 at 19:19
  • The problem is you are trying to figure out how to change the color of a word or the string containing that word, correct? – Mike - SMT Jul 24 '17 at 19:22
  • Yes, and I just updated the code I posted so anyone can just copy, paste, run, – Jake Jul 24 '17 at 19:31
  • I added images to clerify. – Jake Jul 24 '17 at 19:43
  • Ty for the image. I did understand what you were wanting. I do not know if you change just the one word. I know it can be done in a text box and maybe using the same method it can be done here as well. Let me look into and I will reply soon. – Mike - SMT Jul 24 '17 at 19:44
  • Thank you, I also have seen it done with text boxes, but menus don't have the tag attribute which are what you use for text boxes, bummer they didn't think to integrate the same feature... – Jake Jul 24 '17 at 19:48

3 Answers3

1

According to the documentation for OptionMenu here and here I don't think there is a way to set the color of text.

You might be able to get something close to what you want by using a listBox instead. See post here for the listBox example.

Mike - SMT
  • 14,784
  • 4
  • 35
  • 79
  • Thank you for trying, I too considered listBoxs but they always feel too clunky to use and generally not worth sacrificing minimalism for customization. – Jake Jul 24 '17 at 20:11
  • 1
    You could consider creating your own OptionMenu. It might take a bit of code but in the end you would have a custom OptionMenu with the ability to do whatever you designed it to do :). I had to do the same with the scrollBars because you cannot change the colors of tkinters scrollbars in windows. So I made my own so I could. – Mike - SMT Jul 24 '17 at 20:16
  • Interesting, did you just do this by making your own class that emulated the class in Tkinter.py but with custom changes? – Jake Jul 24 '17 at 20:23
  • It was actually written by someone else but I was working on it until they posted it as an answer to a question I had some time ago. Its 278 lines of code all for just a scroll bar. The post where I got the code from is [here](https://stackoverflow.com/questions/43836557/other-option-for-colored-scrollbar-in-tkinter-based-program) so you can see how it compares to tkinters version. – Mike - SMT Jul 24 '17 at 20:29
  • After looking into that, I think the best option is to try to use Menu() to configure a custom OptionMenu, as it is what the OptionMenu uses to create itself in Tkinter. – Jake Jul 24 '17 at 20:56
  • 1
    @Jake Come back and answer your own question once you have it figured out. I would like to see what you did to get this to work. – Mike - SMT Jul 24 '17 at 20:59
  • Took a while, but finally got it! It was a great suggestion to create a custom OptionMenu, thank you for the help! – Jake Jul 25 '17 at 00:15
1

Found a solution! Using a Menu inside of a MenuButton the same way Tkinter creates MenuOptions, I was able to create a custom MenuOption. If you want to add more options, you can use the menbutton.configure() option to edit the button, and menbutton.menu to edit the menu items.

import Tkinter as tk     
from Tkinter import Menu, Menubutton

class Vars():

    global vari
    vari = {}

    def GetVars(self, var):

        return vari.get(str(var))

    def SendVars(self, var, val):

        vari[str(var)] = val


class App():

    def buttselect(self, link, menbutton, selectMenu):
        var = Vars()
        var.SendVars("Selection", link) # Store selected event
        menbutton.configure(text=link) # Set menu text to the selected event

    def prnt(self, link):
        var = Vars()

        print var.GetVars("Selection") # Print event

    def __init__(self, selectMenu):
        events = " "
        options = []
        links = []
        forms = ["Yolo ","Dad? Closed","Anotha One","Normies! Closed"] #This is so you can try it for yourself

        menbutton =  Menubutton (selectMenu, text="--None Selected--", relief="raised")
        menbutton.grid()
        menbutton.menu  =  Menu (menbutton, tearoff=0)
        menbutton["menu"]  =  menbutton.menu

        #Get a list of event names
        for x in forms:
            info = x #Again, this is so you can try it for yourself
            #If desired event keyword is in an event name, add it to the correct links
            if events in info.lower():
                links.append(x)

        #Remove duplicates
        for link in range(0,len(links)):
            options.append(links[link])
        list(set(options))

        #Final list of event names turned into menu commands
        for link in options:

            if "Closed" in link:
                menbutton.menu.add_command( label= link, command= lambda link=link: self.buttselect(link, menbutton, selectMenu), foreground='red')
            else:
                menbutton.menu.add_command( label= link, command= lambda link=link: self.buttselect(link, menbutton, selectMenu))

        b = tk.Button(selectMenu, text="Selection", command= lambda link=link: self.prnt(link)) #Print selected event
        b.pack()

        msg = "Which one would you like to attend?"
        label = tk.Label(selectMenu, text=msg, font="Helvedica 14")

        label.pack(side='top', pady=10)
        menbutton.pack(side="top", pady=10)     


selectMenu = tk.Tk()
selectMenu.attributes('-topmost', True)
app = App(selectMenu)
selectMenu.mainloop()   

This results in exactly the result desired:

Jake
  • 999
  • 1
  • 7
  • 16
1

I found a way!

Let's say x is an optionmenu with options:

options=['Red','Blue','Green']

defopt=tk.StringVar(options[0])   #StringVariable to hold the selected option.

x=tk.OptionMenu(self.optmenuframe,defopt,*options)

Now, get the menu object from the optionmenu and use entryconfig method. That's it!

x.children['menu'].entryconfig(0,foreground='red')
x.children['menu'].entryconfig(1,foreground='blue')
x.children['menu'].entryconfig(2,foreground='green')

#0 is the index of the option you want to apply the configurations to.
fcdt
  • 2,371
  • 5
  • 14
  • 26