I am new to tkinter and python in general. I am trying to create a window that allows the user to input information (based on Entry and dropdown menus) and based on their choices, some new input will show up which will then be used to calculate the results. I've tried making a minimum reproducible snippet of code, as the original code is quite long.
The problem is that in the buttons I don't understand which command to include so that the program waits for all input before executing the rest of the code. Now it seems that no matter what I include it goes directly to the result part of the code.
I've tried having a function that saves the input and calculates the result as the command for the button, but it still does not wait.
The wait_variable as far as I understood only works for one variable?
import tkinter as tk
root = tk.Tk()
root.geometry("1500x800")
Intro_Label = tk.Label(root, text = "Welcome")
Intro_Label.grid(row=0, column=0)
entry_1 = tk.Entry()
entry_1.insert(0, 2.5) #default value
Label_1 = tk.Label(root, text="Input 1")
Label_1.grid(row=2, column=0)
entry_1.grid(row=2, column=1)
Label_2 = tk.Label(root, text="Input 2 ")
#Options for dropdown menu for transport method
I2_clicked = tk.StringVar()
I2_clicked.set("Choose from dropdown menu")
input2_opt = ["a", "b"]
input2 = tk.OptionMenu( root , I2_clicked , *input2_opt )
Label_3 = tk.Label(root, text="Input 2 ")
#Options for dropdown menu for transport method
I3_clicked = tk.StringVar()
I3_clicked.set("Choose from dropdown menu")
input3_opt = ["x", "y"]
input3 = tk.OptionMenu( root , I3_clicked , *input3_opt )
Label_2.grid(row=3, column=0)
input2.grid(row=3, column=1)
Label_3.grid(row=3, column =3)
input3.grid(row=3, column = 4)
def input_calculations():
first_input = entry_1.get()
if I2_clicked.get() == "a":
if I3_clicked.get() == "x":
entry_4 = tk.Entry()
Label_4 = tk.Label(root, text="Input for x|a")
entry_4.insert(0, 5) #dummy default value
entry_4.grid(row = 4, column = 1 )
Label_4.grid(row = 4, column = 0)
entry_5 = tk.Entry()
Label_5 = tk.Label(root, text="Second input for x|a")
entry_5.insert(0, 4) #dummy default value
entry_5.grid(row = 4, column = 4)
Label_5.grid(row = 4, column = 3)
#wait for both inputs before executing the calculations
save_button = tk.Button(root, text ="Calculate results", command= )
save_button.grid(row = 5, column = 6)
#calculate some results
result = float(entry_4.get())* float(entry_5.get())
elif I3_clicked.get() == "y":
entry_6 = tk.Entry()
Label_6 = tk.Label(root, text="Input for y|a")
entry_6.insert(0, 6) #dummy default value
entry_6.grid(row = 4, column = 1 )
Label_6.grid(row = 4, column = 0)
entry_7 = tk.Entry()
Label_7 = tk.Label(root, text="Second input for y|a")
entry_7.insert(0, 7) #dummy default value
entry_7.grid(row = 4, column = 4)
Label_7.grid(row = 4, column = 3)
entry_8 = tk.Entry()
Label_8 = tk.Label(root, text="Third input for y|a")
entry_8.insert(0, 8) #dummy default value
entry_8.grid(row = 4, column = 6)
Label_8.grid(row = 4, column = 5)
save_button = tk.Button(root, text ="Calculate results", command= )
save_button.grid(row = 5, column = 6)
#wait for input before executing the next lines - what to insert here ??
result = float(entry_6.get()) / float(entry_7.get()) * float(entry_8.get())
#continues for all combinations (b and y, b and x) - different inputs, different calculations for each combo
return result
btn = tk.Button(root, text="Confirm", width=15,command=input_calculations)
btn.grid(row= 10, column= 5)
root.mainloop()
You could link the buttons to functions that do the calculations.
Example function:
def button_pressed():
result = float(entry_6.get()) / float(entry_7.get()) * float(entry_8.get())
You could either pass the entries as arguments in a lambda, or make the whole program inside of a class. This way every method can access all of the widgets.
For your save button you would then need to add the function to the command parameter:
save_button = tk.Button(root, text ="Calculate results", command=button_pressed)
You could make multiple functions / methods if you use a class to do the steps you need.
Related
I am trying to make a Python program that asks the user for a number then reverses it using recursion. My attempt is below, but my code gives me TypeError: unsupported operand type(s) for //: 'Entry' and 'int' - any ideas?
from tkinter import *
def reverseInteger(n, r):
if n==0:
return r
else:
return reverseInteger(n//10, r*10 + n%10)
window = Tk()
window.title("Reverse Integer")
frame1 = Frame(window)
frame1.pack()
number = StringVar()
numEntry = Entry(frame1, textvariable=number)
btGetName = Button(frame1, text = "Calculate", command = reverseInteger(numEntry, 0))
label3 = Label(frame1)
numEntry.grid(row = 1, column = 1)
btGetName.grid(row = 1, column = 2)
label3.grid(row = 2, column = 1, sticky="w")
window.mainloop()
Your recursive function is perfectly fine but there are several other
problems in your code.
The main one is that the command parameter of Button must be the
function that will be called when the user presses on the buttton. In
your code, command is set to the return value of reverseInteger
which is an int. So there is a problem here.
Also it seems to me that you want to put the result of your
calculation in label3 so your StringVar should be attached to it
and not to numEntry.
So here is a version that seems ok to me:
from tkinter import *
def reverseInteger(n, r):
if n==0:
return r
else:
return reverseInteger(n//10, r*10 + n%10)
def reverse(): # called when the user click on the button
value = reverseInteger(int(numEntry.get()), 0)
number.set(value) # change the text of the label
window = Tk()
window.title("Reverse Integer")
frame1 = Frame(window)
frame1.pack()
number = StringVar()
numEntry = Entry(frame1)
btGetName = Button(frame1, text = "Calculate", command = reverse)
label3 = Label(frame1, textvariable=number)
numEntry.grid(row = 1, column = 1)
btGetName.grid(row = 1, column = 2)
label3.grid(row = 2, column = 1, sticky="w")
window.mainloop()
I need to create a couple of Labels and Entry fields using Tkinker, they all will be the same, only difference is a text in the label which i could have in a list.
This is what the problem looks like while done in a simple way, i want to do it smarter, using some kind of loop, so i could expand it.
from tkinter import *
root = Tk()
question1 = Label(root, text="Please give data number one")
question1.grid(row=1, column=0)
field1 = Entry(root)
field1.grid(row=1, column=1)
question2 = Label(root, text="Please give data number two")
question2.grid(row=2, column=0)
field2 = Entry(root)
field2.grid(row=2, column=1)
question3 = Label(root, text="Please give data number three")
question3.grid(row=3, column=0)
field3 = Entry(root)
field3.grid(row=3, column=1)
question4 = Label(root, text="Please give data number four")
question4.grid(row=4, column=0)
field4 = Entry(root)
field4.grid(row=4, column=1)
data1 = field1.get()
data2 = field2.get()
data3 = field3.get()
data4 = field4.get()
root.mainloop()
I thought abour something like this but i don't know how to get values from Enter widgets.
from tkinter import *
root = Tk()
questions = ["Please give data number one",
"Please give data number two"
"Please give data number three"
"Please give data number four"
]
for question in enumerate(questions):
ask = Label(root, text=question[1])
ask.grid(row=(question[0] + 1), column=0)
field = Entry(root)
field.grid(row=(question[0] + 1), column=1)
root.mainloop()
You need to do two things:
Firstly keep a reference to the widget, and then use the get() method to get the string.
For an example:
self.entry = Entry(...)
...some code
print("the text is", self.entry.get())
Sample Get Entries:
class InputPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self,parent)
label = Label(self, text="Please give data number four")
label.grid(row=0, column=0, sticky ='n', columnspan =2)
# i brought your variable in the class for example sake
namesInput = ["First:", "second:", "Third:", "Fourth:", "Fifth:"]
self.entryWidgets = [] # we want to call this in another function so we assign it as self.variableName
labelWidgets = []
#LOOP TO CREATE WIDGETS
for i in range(0, len(namesInput)):
labelWidgets.append(Label(self, text = namesInput[i]))
self.entryWidgets.append(Entry(self))
labelWidgets[-1].grid(row= i+1, column =0, sticky='e')
self.entryWidgets[-1].grid(row= i+1, column = 1, sticky='w')
submit = Button(self, text = "Submit", command = self.getEntries)
submit.grid(row = 6, column =0, columnspan =2)
def getEntries(self):
results = []
for x in self.entryWidgets: # i.e for each widget in entryWidget list
results.append(x.get())
print(results)
I am trying to measure some value with sensors and display it using python tkinter GUI. I managed to create a GUI and the program to measure. Now I want to display the data in the GUI and as I am getting new values every second I want to update the screen with new values. I have seen than I can use textvariable. But how to initialize this? when program start, as there is no any output in the beginning, it shows error. How to manage it. any suggestions please. finally how to update every second?
from tkinter import *
import tkinter.font
import numpy as np
import pigpio
win = Tk()
myFont = tkinter.font.Font(family = 'Verdana', size = 20, weight = 'bold')
win.geometry('800x480')
win.configure(background='#CD5C5C')
#------------------------------------------------------main program ----------------------------------#
def readSensors():
#function body
# output is a list with name measuredValues
#measuredValues contains total 4 values as I have 4 sensors
win.after(1000, readSensors) #calling the function every second
#label names variable
output_1= StringVar()
output_2 = StringVar()
output_3 = StringVar()
output_4 = StringVar()
value0 = str(measuredValues[0])
value1= str(measuredValues[1])
value2 = str(measuredValues[2])
value3 = str(measuredValues[3])
output_1.set (value0)
output_2.set (value1)
output_3.set (value2)
output_4.set(value3)
#Labels
# i used textvariable to to measured values. but doesn't work so far
#display values
output_1_label = Label(win, textvariable = output_1,height =2, width = 12)
output_1_label.place(x=200, y=100)
output_2_label = Label(win, textvariable = output_2, height =2, width = 12)
output_2_label.place(x=200, y=200)
output_3_label = Label(win, textvariable = output_3,height =2, width = 12)
output_3_label.place(x=200, y=300)
output_4_label = Label(win, textvariable = output_4, height =2, width = 12)
output_4_label.place(x=200, y=400)
#how to update the window with new data?
win.after(1000, readSensor)
win.mainloop()
You need to update the variables set as textvariables with the sensor values last read:
Something like this - the sensor readings were replaced with a randomly chosen value to simulate new data readings:
import tkinter as tk
import random
def readSensors():
output_1.set(random.choice([0, 1, 2, 3, 4, 5]))
output_2.set(random.choice([0, 1, 2, 3, 4, 5]))
output_3.set(random.choice([0, 1, 2, 3, 4, 5]))
output_4.set(random.choice([0, 1, 2, 3, 4, 5]))
win.after(1000, readSensors)
win = tk.Tk()
win.geometry('800x480')
win.configure(background='#CD5C5C')
output_1 = tk.StringVar()
output_2 = tk.StringVar()
output_3 = tk.StringVar()
output_4 = tk.StringVar()
measuredValues = [0, 1, 2, 3, 4, 5]
value0 = str(measuredValues[0])
value1 = str(measuredValues[1])
value2 = str(measuredValues[2])
value3 = str(measuredValues[3])
output_1.set(value0)
output_2.set(value1)
output_3.set(value2)
output_4.set(value3)
output_1_label = tk.Label(win, textvariable=output_1, height=2, width=12)
output_1_label.place(x=200, y=100)
output_2_label = tk.Label(win, textvariable=output_2, height=2, width=12)
output_2_label.place(x=200, y=200)
output_3_label = tk.Label(win, textvariable=output_3, height=2, width=12)
output_3_label.place(x=200, y=300)
output_4_label = tk.Label(win, textvariable=output_4, height=2, width=12)
output_4_label.place(x=200, y=400)
win.after(1000, readSensors)
win.mainloop()
You can use Classes to reach all the data from parent structure. You need to initilize a function to call another function with after tribute inside it first. It simply configures the data again and again after counting firstly 1000 ms and then 20 ms(adjust it to read data smoothly). You can add more dynamic data/text and use "after" tribute once, it will still be refreshing all of them. It is an event dependent solution which is significantly better than time dependent or loop based refreshing algorithms for data reading.
import time
from random import random
from random import seed
from tkinter import StringVar,Entry
import tkinter as tk
class GUI:
#------------------INITIAL---------------------------------------------------------------------------------------------------------
def __init__(self, parent):
self.labelBackground = tk.Label(parent, text="",bg="white",width=1920,height=1080)
self.labelBackground.place(x=0,y=0)
self.labelDate = tk.Label(parent, text="Date",bg="white", font="Arial 20", width=100)
self.labelDate.pack()
self.labelDate.after(1000, self.refresh_label)
def dateData(self):
year,mon,day,hour,min,sec,a,b,c = time.localtime()
infoDate = f"Date/Time: {year} {mon} {day} h:{hour} m:{min} s:{sec} "
return f"Clock: {hour}:{min}:{sec} "
def refresh_label(self):
self.seconds = self.dateData()
self.labelDate.configure(text=self.seconds)
self.labelDate.after(20, self.refresh_label)
if __name__ == "__main__":
root = tk.Tk()
root.geometry("1920x1080") #Window Resolution
root.title("Insert_Window_Title")
timer = GUI(root)
root.mainloop()
I am trying to use .grid to format my GUI, but it is not doing anything. Here below is my code and my desired layout!
Here is the code I am using. I am quite new to Python...
I am not sure of other methods of formatting except for .grid so any other options would be great too!
from tkinter import *
class PayrollSummary:
def __init__(pay):
window = Tk()
window.title("Employee Payroll")
#Add Frame 1
frame1 = Frame(window)
frame1.pack()
#Add ReadFile Button
btReadFile = Button(frame1, text = "Read File")
btReadFile.pack()
#Add ShowPayroll Button
btShowPayroll = Button(frame1, text = "Show Payroll")
btShowPayroll.pack()
#Add FindEmployee by Name Button
btFindEmployee = Button(frame1, text = "Find Employee by Name")
btFindEmployee.pack()
#Add Highest Radio Button
rbHigh = Radiobutton(frame1, text = "Highest")
rbHigh.pack()
#Add Lowest Radio Button
rbLow = Radiobutton(frame1, text ="Lowest")
rbLow.pack()
#Add FindEmployee by Amount Button
btFindEmployee_A = Button(frame1, text = "Find Employee by Amount")
btFindEmployee_A.pack()
#Add WriteOutput Button
btOutput = Button(frame1, text = "Write Output to File")
btOutput.pack()
#Add Cancel Button
btCancel = Button(frame1, text = "Cancel")
btCancel.pack()
btReadFile.grid(row = 1, column = 2)
btShowPayroll.grid(row = 2, column = 2)
btFindEmployee.grid(row = 2, column = 4)
rbHigh.grid(row = 3, column = 2)
rbLow.grid(row = 3, column = 4)
btFindEmployee_A.grid(row = 3, column = 6)
btOutput.grid(row = 4, column = 2)
btCancel.grid(row = 4, column = 4)
window.mainloop()
PayrollSummary()
pack(), grid() and place() are three methods to put widgets in window (or in other widget).
If you use grid() with some widget then don't use pack() or place().
Doc on effbot.org: grid, pack, place
I removed all .pack() except frame.pack() and get almost what you expected.
Now widgets need to be aligned to left ('west') with sticky='w'
And after adding second Frame I got
Code:
from tkinter import *
class PayrollSummary:
def __init__(pay):
window = Tk()
window.title("Employee Payroll")
#Add Frame 1
frame1 = Frame(window)
frame1.pack()
#Add ReadFile Button
btReadFile = Button(frame1, text = "Read File")
#Add ShowPayroll Button
btShowPayroll = Button(frame1, text = "Show Payroll")
#Add FindEmployee by Name Button
btFindEmployee = Button(frame1, text = "Find Employee by Name")
#Add Highest Radio Button
rbHigh = Radiobutton(frame1, text = "Highest")
#Add Lowest Radio Button
rbLow = Radiobutton(frame1, text ="Lowest")
#Add FindEmployee by Amount Button
btFindEmployee_A = Button(frame1, text = "Find Employee by Amount")
#Add WriteOutput Button
btOutput = Button(frame1, text = "Write Output to File")
#Add Cancel Button
btCancel = Button(frame1, text = "Cancel")
btReadFile.grid(row = 1, column = 2, sticky='w')
btShowPayroll.grid(row = 2, column = 2, sticky='w')
btFindEmployee.grid(row = 2, column = 4, sticky='w')
rbHigh.grid(row = 3, column = 2, sticky='w')
rbLow.grid(row = 3, column = 4, sticky='w')
btFindEmployee_A.grid(row = 3, column = 6, sticky='w')
btOutput.grid(row = 4, column = 2, sticky='w')
btCancel.grid(row = 4, column = 4, sticky='w')
#Add Frame 2
frame2 = Frame(window, bg='red')
frame2.pack(fill='both') # try without `fill`
label2 = Label(frame2, text='Label in bottom Frame', bg='green')
label2.pack()
window.mainloop()
PayrollSummary()
I am trying to create a standard user ID/PASS login. When I use the next function to check if the entered password and name are right, I always get the "wrong values entered" message. Basically, the variables entry_1 and entry_2 are not storing the input text and I want a solution for that. Maybe any of you guys might propose a solution for that?
I have tried to assign entry_1 and entry_2 to variables but it did'nt work out.
from tkinter import *
root = Tk() # creates a window and initializes the interpreter
root.geometry("500x300")
name = Label(root, text = "Name")
password = Label(root, text = "Password")
entry_1 = Entry(root)
entry_2 = Entry(root)
name.grid(row = 0, column = 0, sticky = E) # for name to be at right use sticky = E (E means east)
entry_1.grid(row = 0, column =1)
x = "Taha"
password.grid(row = 1, column = 0)
entry_2.grid(row = 1, column =1)
y = "123"
c = Checkbutton(root, text = "Keep in logged in").grid(columnspan = 2 ) # mergers the two columns
def next():
if a == entry_1 and b == entry_2:
print ("Proceed")
else:
print("wrong values entered")
def getname():
return name
Next = Button(root, text = "Next", command=next).grid(row = 3, column = 1)
root.mainloop() # keep runing the code
I want the program to return "Proceed" once correct values are entered.
in your code you're not checking for the user input anywhere. You should use get() to return user input. I've modified your code accordingly. Now if you enter Taha as username and 123 as password, you'll get the "Proceed" message.
from tkinter import *
root = Tk() # creates a window and initializes the interpreter
root.geometry("500x300")
name = Label(root, text="Name")
password = Label(root, text="Password")
entry_1 = Entry(root)
entry_2 = Entry(root)
name.grid(row=0, column=0, sticky=E) # for name to be at right use sticky = E (E means east)
entry_1.grid(row=0, column=1)
x = "Taha"
password.grid(row=1, column=0)
entry_2.grid(row=1, column=1)
y = "123"
c = Checkbutton(root, text="Keep in logged in").grid(columnspan=2) # mergers the two columns
def next_window():
user_name = entry_1.get()
user_pass = entry_2.get()
if x == user_name and y == user_pass:
print("Proceed")
else:
print("wrong values entered")
def get_name():
return name
Next = Button(root, text="Next", command=next_window).grid(row=3, column=1)
root.mainloop()
thanks to the people who helped, with your help i could find the missing part in the code. i should have used .get() funtion in order to get the entered text back.
here is the upgraded code with some improvements.
from tkinter import *
from tkinter import messagebox
root = Tk() # creates a window and initializes the interpreter
root.geometry("500x300")
name = Label(root, text = "Name")
password = Label(root, text = "Password")
entry_1 = Entry(root)
entry_2 = Entry(root)
name.grid(row = 0, column = 0, sticky = E) # for name to be at right use sticky = E (E means east)
entry_1.grid(row = 0, column =1)
x = "Taha"
password.grid(row = 1, column = 0)
entry_2.grid(row = 1, column =1)
y = "123"
c = Checkbutton(root, text = "Keep in logged in").grid(columnspan = 2 ) # mergers the two columns
def next():
a = entry_1.get()
b = entry_2.get()
if a == "Taha" and b =="123":
messagebox.showinfo("Login", "successfuly logged in ")
root.destroy()
print ("Proceed")
else:
messagebox.showerror("Error", "wrong values entered")
print("wrong values entered")
root.destroy()
Next = Button(root, text = "Next", command=next).grid(row = 3, column = 1)
root.mainloop() # keep runing the code