I'm trying to put multiple colors on a single button in Tkinter. This is what I came up with:
from Tkinter import *
master = Tk()
buttons = {}
def press(clicked):
print clicked
return
for i in range(1,7):
button_name = 'button '+str(i)
buttons[i] = Button(master, text=button_name, command=lambda method=button_name:press(method))
buttons[i].grid(row=0, column=i-1, padx=15)
buttons[i].update()
tot_x = buttons[i].winfo_width()
tot_y = buttons[i].winfo_height()
redframe = Frame(buttons[i], width=tot_x/6, background='red')
blueframe = Frame(buttons[i], width=tot_x/6*5, background='blue')
redframe.place(x=0, y=0, relheight=1)
blueframe.place(relx=1./6, y=0, relheight=1)
master.mainloop()
The problem is it that it makes buttons barely clickable because frames somehow interfere with "clickability" of the buttons. And also colored frames just disappear suddenly when the cursor is placed on their position.
Is there a way to make these frames stay on the buttons and to make them not stop a click?
Arguably, the simplest approach might be to create an image with the colors that you want, and then use the image in the button along with the text.
Though I think Bryan's answer is simpler and fully solves the problem, you can solve the "clickability" issue with bindings (I did not experienced the second issue, so my answer is not addressing it).
The idea is to bind mouse clicks on the frames to trigger a click on the button and restore the usual button behavior. In my example below, I have bound both <ButtonPress-1> and <ButtonRelease-1> to see the button relief effects. I have also bound <Enter> and <Leave> to implement the button color change when the mouse is over it.
from Tkinter import *
master = Tk()
buttons = {}
def press(clicked):
print clicked
def frame_enter(redframe, blueframe):
redframe.configure(background='coral1')
blueframe.configure(background='royalblue1')
def frame_leave(redframe, blueframe):
redframe.configure(background='red')
blueframe.configure(background='blue')
def on_press(event, button):
button.event_generate('<ButtonPress-1>', x=event.x, y=event.y)
def on_release(event, button):
button.event_generate('<ButtonRelease-1>', x=event.x, y=event.y)
for i in range(1,7):
button_name = 'button '+str(i)
buttons[i] = Button(master, text=button_name, command=lambda method=button_name:press(method))
buttons[i].grid(row=0, column=i-1, padx=15)
buttons[i].update()
tot_x = buttons[i].winfo_width()
tot_y = buttons[i].winfo_height()
redframe = Frame(buttons[i], width=tot_x/6, background='red')
blueframe = Frame(buttons[i], width=tot_x/6*5, background='blue')
redframe.place(x=0, y=0, relheight=1)
blueframe.place(relx=1./6, y=0, relheight=1)
redframe.bind('<ButtonPress-1>', lambda e, b=buttons[i]: on_press(e, b))
blueframe.bind('<ButtonPress-1>', lambda e, b=buttons[i]: on_press(e, b))
redframe.bind('<ButtonRelease-1>', lambda e, b=buttons[i]: on_release(e, b))
blueframe.bind('<ButtonRelease-1>', lambda e, b=buttons[i]: on_release(e, b))
redframe.bind('<Enter>', lambda e, rf=redframe, bf=blueframe: frame_enter(rf, bf))
blueframe.bind('<Enter>', lambda e, rf=redframe, bf=blueframe: frame_enter(rf, bf))
redframe.bind('<Leave>', lambda e, rf=redframe, bf=blueframe: frame_leave(rf, bf))
blueframe.bind('<Leave>', lambda e, rf=redframe, bf=blueframe: frame_leave(rf, bf))
master.mainloop()
Edit: Keeping the buttons is not necessary, they can be replaced by frames. This way, no need to use place, the colored frames can just be packed inside:
from Tkinter import *
master = Tk()
buttons = {}
def press(clicked):
print clicked
def frame_enter(redframe, blueframe):
redframe.configure(background='coral1')
blueframe.configure(background='royalblue1')
def frame_leave(redframe, blueframe):
redframe.configure(background='red')
blueframe.configure(background='blue')
def on_press(event, widget):
widget.configure(relief='sunken') # mimic button's relief effect on click
def on_release(event, widget, text):
widget.configure(relief='raised') # mimic button's relief effect on click
press(text)
for i in range(1,7):
button_name = 'button '+ str(i)
buttons[i] = Frame(master, relief='raised', width=78, height=24, bd=2)
buttons[i].grid(row=0, column=i-1, padx=15)
buttons[i].update_idletasks()
tot_x = buttons[i].winfo_width()
tot_y = buttons[i].winfo_height()
redframe = Frame(buttons[i], width=tot_x/6, height=tot_y, background='red')
blueframe = Frame(buttons[i], width=tot_x/6*5, height=tot_y, background='blue')
redframe.pack(side='left')
blueframe.pack(side='left')
redframe.bind('<ButtonPress-1>', lambda e, b=buttons[i]: on_press(e, b))
blueframe.bind('<ButtonPress-1>', lambda e, b=buttons[i]: on_press(e, b))
redframe.bind('<ButtonRelease-1>', lambda e, b=buttons[i], t=button_name: on_release(e, b, t))
blueframe.bind('<ButtonRelease-1>', lambda e, b=buttons[i], t=button_name: on_release(e, b, t))
redframe.bind('<Enter>', lambda e, rf=redframe, bf=blueframe: frame_enter(rf, bf))
blueframe.bind('<Enter>', lambda e, rf=redframe, bf=blueframe: frame_enter(rf, bf))
redframe.bind('<Leave>', lambda e, rf=redframe, bf=blueframe: frame_leave(rf, bf))
blueframe.bind('<Leave>', lambda e, rf=redframe, bf=blueframe: frame_leave(rf, bf))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With