tkinter: input entry & generate result without button press - python

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)

Related

Dictionary within a function passing values to another function

I am having an issue with my code. I am relatively new at coding. My issue is that I am trying to take the dictionary SeatingOrder populated in the Waitlist.GuestList function and then pass those values, if there are any, to the Staff function so that I can display them in a drop-down and modify them. I can't seem to find a way to do it and any help or even a point in the right direction would be helpful.
import math
from tkinter import *
import time
#initializes time based on system time
count= int(0)
t= time.localtime()
current_Time = float(time.strftime("%H%M%S", t))
SeatingOrder = {''}
root=Tk()
root.title("Main Screen")
root.geometry("1920x1080")
def WaitList():
#tnikter screen setup
root=Tk()
root.title("Seating List")
root.geometry("1920x1080")
#creates label and entry box
PartyName = Entry(root)
PartyName.grid(row=0, column=1)
Label(root,text="Enter the party name: ").grid(row=0, column=0)
#creates label and entry box
PartySize = Entry(root)
PartySize.grid(row=0, column=3)
Label(root, text="How many are in your party? ").grid(row=0, column=2)
#creates a dictionary with an array inside of it so information can be search by the key value
SeatingOrder = {PartyName : [PartySize, current_Time]}
#defintion to populate array
def GuestList():
x = str(PartyName.get())
y = int(PartySize.get())
SeatingOrder = {x : [y, current_Time]}
#Prints statement and displays the result
Label(root, text="Your spot has been saved!").grid(row=3, column=1)
Label(root, text=SeatingOrder).grid(row=3, column=2)
#creates a button the runs the command.
Button(root, text="Save", command=GuestList).grid(row=1, column=1)
Button(root, text="x", command=root.destroy).grid(row=1, column=10)
root.mainloop()
return SeatingOrder
def Staff():
Dictionary = WaitList()
root=Tk()
root.title("Administration")
root.geometry("1920x1080")
def show():
Label(root, Text=clicked.get()).grid(row=1, column=1)
clicked = StringVar()
clicked.set("Please select a party")
SeatingDropDown = OptionMenu(root, clicked, )
SeatingDropDown.grid(row=0, column=1)
Button(root, text="select", command=show).grid(row=0, column=2)
Button(root, text="x", command=root.destroy).grid(row=1, column=10)
exit
Button(root, text="Waitlist", command=WaitList).grid(row=5, column=1)
Button(root, text="Staff", command=Staff).grid(row=5, column=2)
root.mainloop()
Just one point is that in this code you have set up a root main screen window and for each function you have set up a new root window (note that Staff window has no mainloop call and so wouldn't have an event loop)
But I would scrap all that. The usual way with tkinter is to have a root (Main screen) and all subsequent windows are made tkinter.Toplevel with the root as master. Skeleton example for just this point:
import tkinter as tk
root - tk.Tk()
root.geometry('1920x1080+0+0') # geometry is 'widthxheight+x+y'
WaitListwindow = tk.Toplevel(root)
WaitListwindow.pack()
WaitListwindow.place(x=10,y=10) #place values are now relative to the root geometry
Staffwindow = tk.Toplevel(root)
Staffwindow.pack()
Staffwindow.place(x=70,y=10)
root.mainloop()
now root is the parent\master and WaitListWindow and StaffWindow are the children. Note that I use pack and place but grid applies just as well with the appropriate parameters.
You can then place the buttons and entry as children of the appropraite window, eg
staffselectb = tk.Button(Staffwindow)
staffselectb.pack()
staffselectb.place(x=5,y=5) # this button is now relative to Staffwindow placement
#so that x and y are inside Staffwindow at (5,5)
With the root.mainloop() you can now bind events to a widget, eg to retrieve the Entry widget contents.
There is more but I just wanted to concentrate on this point.

Returning values from entry's when pressing a button using Tkinter

I am writing a program that requires two values (from 2 entries) to be called when a button is pressed. I simplified to code to try to isolate the problem. For some reason the program is not behaving how I want it to. When the button is pressed, the output is "A=" and then if i click the button a second time I get ""A=entry1 B=entry2 A=". I have been trying to figure out the problem for hours now, please help.
import tkinter as tk
def button_function():
A = entry1.get()
print('A=', A)
B= entry2.get()
print('B=', B)
root = tk.Tk()
canvas = tk.Canvas(root)
canvas.pack()
entry1 = tk.Entry(root)
entry1.place(relwidth=0.5, relheight=0.5)
entry2 = tk.Entry(root)
entry2.place(rely=0.5, relwidth=0.5, relheight=0.5)
button = tk.Button(root, text = "confirm", command= button_function)
button.place(relx=0.5, relwidth=0.5, relheight=1)
root.mainloop()
You just need to change command=button_function() to command=button_function, then it will work perfectly!

how to bind button in tkinter

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.

I having trouble running my python Tkinter question

I'm working on a python assignment and this is where I got so far. I'm stuck and cannot execute the application. I'm making a calculator that scores the average and gives a grade letter. I was looking into my professor's video and there was "import tkinter.messagebox as tkm" but Im not sure how to implement this in the code.
this is my code:
import tkinter as tk
import tkinter.messagebox as tkm
window = tk.Tk()
window.geometry('400x400')
window.title("Exam Calculator")
window = tk.Tk()
window.geometry('300x300')
def calculate():
score1 = float(entry1.get())
score2 = float(entry2.get())
score3 = float(entry3.get())
avg = (score1 + score2 + score3)/3
if(avg>=90):
lettergrade= "A"
elif(avg>=80 and avg<=89):
lettergrade = "B"
elif(avg>=70 and avg<=79):
lettergrade= "C"
elif(avg>=60 and avg<=69):
lettergrade = "D"
else:
lettergrade = "F"
label1 = tk.Label(window, text='Test 1')
label1.pack()
entry1 = tk.Entry(window)
entry1.pack()
label2 = tk.Label(window, text='Test 2')
label2.pack()
entry2 = tk.Entry(window)
entry2.pack()
label3 = tk.Label(window, text='Test 3')
label3.pack()
entry3 = tk.Entry(window)
entry3.pack()
button2 = tk.Button(window, text="Calculate",
command=calculate)
Button1 = tk.Button(window, text="quit",
command=window.destroy)
messagebox can help to create fast small message windows.
The usage is very simple, just implement this in your code:
from tkinter import messagebox
In you case:
from tkinter import messagebox as tkm
Then:
messagebox.function(title,message,options)
In your case:
tkm.function(title,message,options)
The functions are:
showinfo(): for showing some relevant informations.
showwarning(): for displaying a warning to the user.
showerror(): for displaying an error message.
askquestion(): for asking a yes/no question to the user.
askokcancel(): confirm the user’s action regarding some application
activity.
askyesno(): for asking a yes/no question about a user action.
askretrycancel(): for asking the user about doing a specific task again.
The options are:
default: this option is used to specify the default button like
ABORT, RETRY, or IGNORE in the message box.
parent: this option is used to specify the window on top of which
the message box is to be displayed.
The code needs just some improvements:
pack() the two buttons (as to display them)
add window.mainloop() at the end of your code (this is why is does not start)
There are multiple problems in your code. First, you define window two times. The second time, you just override your frist instance of window, so just leave that out.
Then you are not packing your Buttons, which means they will not be shown in your window. Lastly, you are missing the most important part of your Tkinter Application, which is to start the applications mainloop, which makes the window pop up and tells Tkinter to start listening for your mouse and keyboard interaction with the window and do something with it. This is called an event loop and is the main component of every graphical user interface. You start the eventloop by calling .mainloop() on your instance of tk.Tk, which is your window variable.
Lastly, it is unclear from your text what you actually want to do with the Messagebox.
I assume that you want to use the message box to display the result of your calculate function, since right now it doesn't do anything.
import tkinter as tk
import tkinter.messagebox as tkm
window = tk.Tk()
window.geometry('400x400')
window.title("Exam Calculator")
def calculate():
score1 = float(entry1.get())
score2 = float(entry2.get())
score3 = float(entry3.get())
avg = (score1 + score2 + score3)/3
if(avg>=90):
lettergrade= "A"
elif(avg>=80 and avg<=89):
lettergrade = "B"
elif(avg>=70 and avg<=79):
lettergrade= "C"
elif(avg>=60 and avg<=69):
lettergrade = "D"
else:
lettergrade = "F"
message = 'Your result is ' + lettergrade
tkm.showinfo(title='Result', message=message)
label1 = tk.Label(window, text='Test 1')
label1.pack()
entry1 = tk.Entry(window)
entry1.pack()
label2 = tk.Label(window, text='Test 2')
label2.pack()
entry2 = tk.Entry(window)
entry2.pack()
label3 = tk.Label(window, text='Test 3')
label3.pack()
entry3 = tk.Entry(window)
entry3.pack()
button2 = tk.Button(window, text="Calculate",
command=calculate)
button2.pack()
Button1 = tk.Button(window, text="quit",
command=window.destroy)
Button1.pack()
window.mainloop()

How to compulsory close message box for Toplevel window

image for that
I have few lines of code here which is login system which works fine but i can click on the Toplevel button multiple times when i provide the wrong password without closing the messagebox.How can i make it so that it has to be closed messagebox before i can make attempt again.
from tkinter import *
from tkinter import messagebox
def top():
if entry1.get() == "333":
log.destroy()
root.deiconify()
else:
messagebox.showerror("error", "try again")
root = Tk()
root.geometry("300x300")
log = Toplevel(root)
log.geometry("200x200")
label1 = Label(log, text="password")
entry1 = Entry(log)
button1 = Button(log, text="login", command=top)
label1.pack()
entry1.pack()
button1.pack(side="bottom")
lab = Label(root, text="welcome bro").pack()
root.withdraw()
root.mainloop()
You need to make the log window the parent of the dialog:
messagebox.showerror("error", "try again", parent=log)
By default it will use the root window (the Tk instance) as the parent which in this case is not what you want.
With hint from #furas this how to implement this:
create another function to the call it when the entry doesn't match and use grab_set method for the Toplevel window tp.grab_set().You can add your customarised image to the Toplevel window as well as message to display in the box(here: i use label to depict that)
from tkinter import *
from tkinter import messagebox
def dialog(): # this function to call when entry doesn't match
tp = Toplevel(log)
tp.geometry("300x100")
tp.title('error')
tp.grab_set() # to bring the focus to the window for you to close it
tp.resizable(width=False, height=False)
l = Label(tp, text="try again\n\n\n\n add your customarize image to the window")
l.pack()
def top():
if entry1.get() == "333":
log.destroy()
root.deiconify()
else:
dialog() # being called here
root = Tk()
root.geometry("300x300")
log = Toplevel(root)
log.geometry("200x200")
label1 = Label(log, text="password")
entry1 = Entry(log)
button1 = Button(log, text="login", command=top)
label1.pack()
entry1.pack()
button1.pack(side="bottom")
lab = Label(root, text="welcome bro").pack()
root.withdraw()
root.mainloop()

Categories