how to bind button in tkinter - python

import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Tic Tac Toe")
root.geometry("505x500")
root.resizable(0,0)
Blank = tk.PhotoImage(file='Blank.png')
X = tk.PhotoImage(file='X.png')
O = tk.PhotoImage(file='O.png')
def configB(event):
print('hello')
btn1 = tk.Button(root,image=Blank)
btn1.place(x=0,y=0)
btn2 = ttk.Button(image=Blank)
btn2.place(x=165,y=0)
btn3 = ttk.Button(image=Blank)
btn3.place(x=330,y=0)
btn4 = ttk.Button(image=Blank)
btn4.place(x=0,y=165)
btn5 = ttk.Button(image=Blank)
btn5.place(x=165,y=165)
btn6 = ttk.Button(image=Blank)
btn6.place(x=330,y=165)
btn7 = ttk.Button(image=Blank)
btn7.place(x=0,y=330)
btn8 = ttk.Button(image=Blank)
btn8.place(x=165,y=330)
btn9 = ttk.Button(image=Blank)
btn9.place(x=330,y=330)
btn1.bind('<Return>',configB)
root.mainloop()
i want to bind btn1 and i want it to work when i press enter but nothing happens when i press enter as per my code it should print hello .
please help thanks in advance.

As #jasonharper said it will work only if button is focused
btn1.focus()
btn1.bind('<Return>', configB)
and if you click other button then it will not work again
so better bind to main winodw
root.bind('<Return>', configB)
Minimal working code
import tkinter as tk
# --- functions --- # PEP8: lower_case_names
def config_b(event):
print('hello')
# --- main ---
root = tk.Tk()
btn1 = tk.Button(root, text='1')
btn1.pack()
btn1 = tk.Button(root, text='2')
btn1.pack()
#btn1.focus()
#btn1.bind('<Return>', config_b)
root.bind('<Return>', config_b)
root.mainloop()

There is no quick answer to this question.
Buttons must be bound so as to duplicate (as close as possible) normal button behaviour.
This includes changing button relief and colors, then restoring button.
Finally it has to execute the button command.
The following example does this for two buttons.
'button' responds to Mouse 'Button-3'
'buttonX' responds to Key 'Return'
import tkinter as tk
def working():
print("Working...")
def actionPress(event):
event.widget.config(
relief = "sunken",
background = "red",
foreground = "yellow")
def actionRelease(event):
event.widget.config(
relief = "raised",
background = "SystemButtonFace",
foreground = "SystemButtonText")
# activate buttons' command on release
event.widget.invoke()
window = tk.Tk()
button = tk.Button(window, text = "press", command = working)
button.pack()
buttonX = tk.Button(window, text = "pressX", command = working)
buttonX.pack()
# bind returns unique ID
boundP = button.bind("<ButtonPress-3>", actionPress)
boundR = button.bind("<ButtonRelease-3>", actionRelease)
boundXP = buttonX.bind("<KeyPress-Return>", actionPress)
boundXR = buttonX.bind("<KeyRelease-Return>", actionRelease)
# This is how to unbind (if necessary)
# button.unbind(""<ButtonPress-3>", boundP)
# button.unbind(""<ButtonRelease-3>", boundR)
# buttonX.unbind(""<KeyPress-Return>", boundXP)
# buttonX.unbind(""<KeyRelease-Return>", boundXR)
window.mainloop()

You don't need parameter in configB method. Also don't need bind for button1. I also add command in button1 widget. Comment out in line 36 #btn1.bind('<Return>',configB)
def configB():
print('hello')
btn1 = tk.Button(root, command=configB)
Result:
Btw, I don't have png image.

Related

Tkinter messagedialog askyesno with a checkbox?

Is it possible to make a Tkinter yes/no messagebox with a checkbox, for something like 'Never ask me again'?
Or would I have to create another window, create my own Labels and CheckButtons, and basically create my own dialog?
You should create your own dialog box then.
Here’s what you can do:
from tkinter import *
def popup():
popupWin = Toplevel()
popupWin.title(“Continue?”)
checkVariable = IntVar()
lbl = Label(popupWin, text=“Continue?)
lbl.pack()
btn2 = Button(popupWin, text=“Yes”)
btn2.pack()
btn3 = Button(popupWin, text=“No”)
btn3.pack()
checkBox = Checkbutton(popupWin, text=“Don’t ask again”, variable=checkVariable)
root = Tk()
btn = Button(root, text=Message Box, command=popup)
root.mainloop()

*Using Eclipse IDE* My button isn't clickable. Python Tkinter

I've been trying for about a week now but I can't seem to figure out what I did wrong. My button will not respond when I click it, and even after adding a command it would just display it when I run the program. If I put the disable command, I can see the button change to disabled. Please help if you can.
from tkinter import *
screen = Tk()
screen.title = ("My first")
screen.geometry("800x500")
#create a label
myLabel1 = Label(screen, text = "First Program")
myLabel2 = Label(screen, text = "Yeah Buddy")
#place onto screen using grid system
myLabel1.grid(row=0,column=0)
myLabel2.grid(row=1,column=1)
#Create a text box:
txtfield = Entry(screen, width=50, bg="blue", fg= "white")
txtfield.grid(row=2, column =2 )
#command for click (you need to have function appear before where you intend to use it for it to execute.)
def myClick():
myResponse = Label(screen, text= "Button clicked" + txtfield.get())
myResponse.grid(row=4, column=2)
#make a button
myButton = Button(screen, text="Test Button", command = myClick())
myButton.grid(row=3, column=2)
screen.mainloop()
You're calling myClick instead of passing the function itself as a parameter. command=myClick

tkinter: input entry & generate result without button press

This is my first attempt at tkinter. I was using this tutorial, code below, where a user input a number, and with a button generate a result at another window.
import tkinter as tk
root= tk.Tk()
canvas1 = tk.Canvas(root, width = 400, height = 300)
canvas1.pack()
entry1 = tk.Entry (root)
canvas1.create_window(200, 140, window=entry1)
def getSquareRoot ():
x1 = entry1.get()
label1 = tk.Label(root, text= float(x1)**0.5)
canvas1.create_window(200, 230, window=label1)
button1 = tk.Button(text='Get the Square Root', command=getSquareRoot)
canvas1.create_window(200, 180, window=button1)
root.mainloop()
How can I do this directly, without the button? I.e., Enter number > result is generated immediately?
How about using bind for this effect, when you press a binded key, the function gets called and executed.
Here is an example:
import tkinter as tk
root = tk.Tk()
entry1 = tk.Entry(root)
entry1.pack(pady=(20, 0), padx=10)
label1 = tk.Label(root)
def getSquareRoot(event=None):
root.after(1000,getSquareRoot)
x1 = entry1.get()
try:
sqrt = float(x1)**0.5
except:
sqrt = ''
label1.config(text=sqrt)
label1.pack()
button1 = tk.Button(text='Get the Square Root', command=getSquareRoot)
button1.pack(pady=(0, 20))
entry1.bind('<Return>', getSquareRoot)
root.after(5000,getSquareRoot)
root.mainloop()
If you press the Enter key at the entry widget, it will generate the output for you, without hitting any buttons.
If you want to display Entry widget contents without using the keyboard then use a mouse key press.
entry1.bind('<Double-Button-1>', getSquareRoot)
or
entry1.bind('<Button-3>', getSquareRoot)

How to get widget name in event?

from tkinter import *
main = Tk()
def flipper(event):
# I'd like to do this:
#if widgetname == switcher:
#do stuff
#if widgetname == switcher1:
#do stuff
return
switcher = Label(main, bg='white', text="click here", font="-weight bold")
switcher.grid()
switcher.bind("<Button-1>", flipper)
switcher1 = Label(main, bg='white', text="click here", font="-weight bold")
switcher1.grid()
switcher1.bind("<Button-1>", flipper)
switcher2 = Label(main, bg='white', text="click here", font="-weight bold")
switcher2.grid()
switcher2.bind("<Button-1>", flipper)
switcher3 = Label(main, bg='white', text="click here", font="-weight bold")
switcher3.grid()
switcher3.bind("<Button-1>", flipper)
switcher4 = Label(main, bg='white', text="click here", font="-weight bold")
switcher4.grid()
switcher4.bind("<Button-1>", flipper)
switcher5 = Label(main, bg='white', text="click here", font="-weight bold")
switcher5.grid()
switcher5.bind("<Button-1>", flipper)
main.mainloop()
In my event function I'd like to do different things based on the label that is clicked. What im stumped on is that I can only get the identifier number of the widget that is clicked, not the name. If I could get the identifier of all my widgets then I could do:
def flipper(event):
if event.widget == switcher.identifier():
do stuff
but I can't find how to get the id of a specified widget either...
How can I get the name of a widget by its identifier (event.widget())?
Or how can I get the identifier of a specified widget name?
If neither are possible, then I'd have to make a different function and bind for each label which is a lot of work that hopefully is not necessary.
Edit:
from tkinter import *
main = Tk()
def flipper(event, switch):
if switch.widget == 's1':
print("got it")
switcher = Label(main, bg='white', text="click here", font="-weight bold")
switcher.grid()
switcher.bind("<Button-1>", flipper)
switcher.widget = 's1'
main.mainloop()
You can't get the variable name that the widget is assigned to, that would be relatively useless. A widget could be assigned to more than one variable, or none at all.
Getting the label text
You have access to the actual widget, and you can use that to get the text that is on the label. Your example shows that all labels are the same, so this might not be useful to you:
def flipper(event):
print("label text:", event.widget.cget("text"))
Using a custom widget name
You can also give a widget a name. You can't get back precisely the name, but you can come very close. For example, if you create a label like this:
switcher = Label(main, name="switcher", bg='white', text="click here", font="-weight bold")
You can get the string representation of the widget by splitting on "." and taking the last value:
def flipper(event):
print("widget name:", str(event.widget).split(".")[-1])
Passing a name via the binding
Finally, you can set up your bindings such that the name is sent to the function:
switcher.bind("<Button-1>", lambda event: flipper(event, "switcher"))
switcher1.bind("<Button-1>", lambda event: flipper(event, "switcher1"))
You can use event.widget to get standard parameters from clicked widget
example:
import tkinter as tk
def callback(event):
print(event.widget['text'])
main = tk.Tk()
switcher = tk.Label(main, text="click here")
switcher.grid()
switcher.bind("<Button-1>", callback)
main.mainloop()
You can assign own variables to widgets
switcher.extra = "Hello"
and then get it
event.widget.extra
example:
import tkinter as tk
def callback(event):
print(event.widget['text'])
print(event.widget.extra)
main = tk.Tk()
switcher = tk.Label(main, text="click here")
switcher.grid()
switcher.bind("<Button-1>", callback)
switcher.extra = "Hello"
main.mainloop()
You can use lambda to bind function with arguments
bind("<Button-1>", lambda event:callback(event, "Hello"))
example:
import tkinter as tk
def callback(event, extra):
print(event.widget['text'])
print(extra)
main = tk.Tk()
switcher = tk.Label(main, text="click here")
switcher.grid()
switcher.bind("<Button-1>", lambda event:callback(event, "Hello"))
main.mainloop()
I had the same issue I found easy way was to use bind method.
apparent name property is private but can be accessed via _name
This is useful if you plan to generate widgets dynamically at runtime
# Import Module
from tkinter import *
# create root window
root = Tk()
# root window title and dimension
root.title("Welcome to Test window")
# Set geometry (widthxheight)
root.geometry('350x200')
#adding a label to the root window
lbl = Label(root, text = "Press a button")
lbl.grid()
#define mouse up event
def mous_up(ev:Event):
#get calling widget from event
sender:Button = ev.widget
#set label text
lbl.configure(text = sender._name + " up")
#read foreground color from button
#If red make green, else make red
if sender.cget('fg') == "red":
#normal color
sender.configure(fg='lime')
#mouse over color
sender.configure(activeforeground='green')
else:
#normal color
sender.configure(fg="red")
#mouse over color
sender.configure(activeforeground='darkred')
#define mouse down event
def mous_down(ev:Event):
lbl.configure(text = str(ev.widget._name) + " down")
# button widget with red color text
# inside
btn = Button(root, text = "Click me" ,
fg = "red",name = "button-A")
#bind mouse up and mouse down events
btn.bind('<ButtonRelease-1>',mous_up)
btn.bind('<Button-1>',mous_down)
# set Button grid
btn.grid(column=0, row=1)
#Create another button
btn = Button(root, text = "Click me2" ,
fg = "red",name="button2")
#bind mouse up and mouse down events
btn.bind('<ButtonRelease-1>',mous_up)
btn.bind('<Button-1>',mous_down)
#absolute placement of button instead of
#using grid system
btn.place(x=50,y=100)
# all widgets will be here
# Execute Tkinter
root.mainloop()
Quick and dirty - you could have the function check a switcher attribute.
def flipper(event, switch):
if switch.widget == 's1':
do_stuff
return stuff
if switch.widget == 's2':
do_stuff
return stuff
switcher1.widget = 's1'
switcher2.widget = 's2'
I know this is an old post, but I had the same problem and I thought I should share a solution in case anyone is interested. You can give your widget a name by creating a subclass of the widget. E.g. "Button" is a widget. You can make a child widget "MyButton" which inherits from button and then add an instance variable to it (e.g. name, uniqueID etc.)
Here is a code snippet
class MyButton(Button):
def __init__(self, master = None, textVal = "", wName = ""):
Button.__init__(self, master, text = textVal)
self.widgetID = wName #unique identifier for each button.
When you want to create a new button widget, use
b = MyButton(.....),
instead of
b = Button(.......)
This way, you have all the functionality of a button, plus the unique identifier.

How to make a button open a new window?

I am making a simple GUI that starts with a main menu them the user can click a button to proceed to a new window which has a picture of a keyboard and the user can press key on their keyboard to play the paino. Right now I cant figure out how to make a button that when pressed closes the main menu (labeled mainMenu()) and open the game menu (playGame).
import tkinter
from tkinter import *
class mainMenu:
def _init_(self, master):
frame = Frame(master)
frame.pack()
self.quitButton = Button(frame, text = "Quit", command = frame.quit)
self.quitButton.pack(side = LEFT)
self.proceedButton = Button(frame, text = "Play", command = playGame)
self.proceedButton.pack(side = LEFT)
def playGame(self):
frame.quit
gameMenu()
def gameMenu(self):
root = Tk()
b = mainMenu(root)
topFrame = Frame(root)
topFrame.pack()
bottomFrame = Frame(root)
bottomeFrame.pack(side = BOTTOM)
photo = PhotoImage(file = "piano.png")
label = Label(root, image = photo)
label.pack()
root.mainloop()
You'll have to forgive me for removing your class but I've never personally worked with classes in python before. However I seem to have you code working to some degree.
import tkinter
from tkinter import *
def playGame():
frame.quit
gameMenu()
def gameMenu():
b = mainMenu(root)
topFrame = Frame(root)
topFrame.pack()
bottomFrame = Frame(root)
bottomFrame.pack(side = BOTTOM)
photo = PhotoImage(file = "piano.png")
label = Label(root, image = photo)
label.pack()
root=Tk()
frame = Frame(root)
frame.pack()
quitButton = Button(frame, text = "Quit", command = frame.quit)
quitButton.pack(side = LEFT)
proceedButton = Button(frame, text = "Play", command = playGame)
proceedButton.pack(side = LEFT)
root.mainloop()
The main problem you had was that you were using both root and master. When declaring the main window in tkinter you normally use either root = Tk() or master = Tk() either one is acceptable, personally I use master. This variable contains the main window that everything else is placed into. You also hadn't put Tk() into any variable, meaning that when you hit root.mainloop() there was nothing to enter the main loop, this was because you were trying to declare root = Tk() inside gameMenu, which wasn't getting called in your program.
If you want to open windows within tkinter it's probably easier to write something like this:
from tkinter import *
master = Tk() #Declaring of main window
def ProceedButtonCommand(mainframe, master): #Command to attach to proceed button
mainframe.destroy()
DrawSecondScreen(master) #This line is what lets the command tied to the button call up the second screen
def QuitButtonCommand(master):
master.destroy()
def DrawFirstScreen(master):
mainframe = Frame(master) #This is a way to semi-cheat when drawing new screens, destroying a frame below master frame clears everything from the screen without having to redraw the window, giving the illusion of one seamless transition
ProceedButton = Button(mainframe, text="Proceed", command=lambda: ProceedButtonCommand(mainframe, master)) #Lambda just allows you to pass variables with the command
QuitButton = Button(mainframe, text = "Quit", command=lambda: QuitButtonCommand(master))
mainframe.pack()
ProceedButton.pack()
QuitButton.pack()
def DrawSecondScreen(master):
mainframe = Frame(master)
Label1 = Label(mainframe, text="Temp")
mainframe.pack()
Label1.pack()
DrawFirstScreen(master)
master.mainloop() #The mainloop handles all the events that occur in a tkinter window, from button pressing to the commands that a button runs, very important
This little script just draws a screen with two buttons, one draws a new screen with the text "temp" on it and the other button closes the master window.
In the future it's probably a better idea to ask a friend who is experienced in programming to help with this kind of stuff. Get talking on some computing forums, I'm sure you'll find a group of sharing and fixing code quickly.

Categories