Tkinter - Making Program Wait for User Input - python

I have a program that calculates a persons BMI after the user gives his height and weight.
I used variable.insert() to insert a value so the program doesn't have errors.
Is there any way to have the program start 'empty' without getting errors? Basically, I need it to not do anything until the calculate button is pressed.
from Tkinter import *
class App(Tk):
def __init__(self):
Tk.__init__(self)
self.height()
self.weigh()
self.output()
self.calculate()
def height(self):
Label(self, text = "Enter Height, feet").grid()
self.feet = Entry(self)
self.feet.grid(row = 0, column = 1)
self.feet.insert(0, "1")
Label(self, text = "Enter Height, inches").grid(row = 1, column = 0)
self.inches = Entry(self)
self.inches.grid(row = 1, column = 1)
self.inches.insert(0, "1")
def weigh(self):
Label(self, text = "Enter Weight").grid(row =2, column = 0)
self.weight = Entry(self)
self.weight.grid(row = 2, column = 1)
self.weight.insert(0, "1")
def output(self):
self.calcBMI = Button(self, text = "Calculate BMI")
self.calcBMI.grid(row = 6, columnspan = 2)
self.calcBMI["command"] = self.calculate
Label(self, text = "Body Mass Index").grid(row = 4, column = 0)
self.lblbmi = Label(self, bg = "#fff", anchor = "w", relief = "groove")
self.lblbmi.grid(row = 4, column = 1, sticky = "we")
Label(self, text = "Status").grid(row = 5, column = 0)
self.lblstat = Label(self, bg = "#fff", anchor = "w", relief = "groove")
self.lblstat.grid(row = 5, column = 1, sticky = "we")
def calculate(self):
ft = int(self.feet.get())
inch = int(self.inches.get())
ht = ft * 12 + inch
wt = int(self.weight.get())
bmi = (wt * 703) / (ht ** 2)
self.lblbmi["text"] = "%.2f" % bmi
if bmi > 30:
self.lblstat["text"] = "Obese"
elif bmi > 25:
self.lblstat["text"] = "Overweight"
elif bmi > 18.5:
self.lblstat["text"] = "Normal"
else:
self.lblstat["text"] = "Underweight"
def main():
app = App()
app.mainloop()
if __name__ == "__main__":
main()

What you are doing right now is calling the output outright(& also by pressing the calculate button). What you need to do is call it only when the button is pressed
From init() remove self.calculate().
Now just remove all the insert statements. You don't need them anymore ;)
Edit:
As Joe suggested in his comment, you could also disable the button until all the fields are populated. You could do this by setting its state to disabled,like this:
self.calcBMI.config(state='disabled')

Related

How to fix this error of python tkinter StringVar?

So basically i am going to write a program of python tkinter to show weight, however the variables and the objects are distracting me.
My code is like this:
from tkinter import *
import tkinter as tk
#object oriented BMI project
class Root(Tk):
def __init__(self):
super(Root, self).__init__()
#Info Bar
self.title("Shushu BMI Calculator")
self.geometry("1100x600")
#self.resizable("False")
#var
self.weight = tk.StringVar()
#self.w = tk.StringVar()
#Caption
self.caption = tk.Label(text = "BMI Calculator - Beta 2.0",
fg = "brown",
font="Arial 40")
self.caption.grid(column = 0, row = 0, sticky = "N")
#Copyright
self.copyright = tk.Label(text = "Powered by Shushu Studio",
fg = "green",
font = "Arial 20")
self.copyright.grid(column = 1, row = 0, sticky = "E")
#Weight input Row
self.weightInputTag = tk.Label(text="Please input your weight here (kg)")
self.weightInputTag.grid(column = 0, row = 1, sticky = "W")
self.weightEntry = tk.Entry(textvariable = self.weight)
self.weightEntry.grid(column = 0, row = 1)
self.weightSubmit = tk.Button(text="Submit",
COMMAND=self.weightget)
self.weightSubmit.grid(column = 0, row = 2)
self.showWeight = tk.Label(text="")
self.showWeight.grid(column = 0, row = 3)
def weightget(self):
weight = self.weightEntry.get()
self.showWeight.configure(text=weight)
root = Root()
root.mainloop()
And the console show this:
Resetting Python state.
Running P:\2020\09\25\bmi.py
The interactive Python process has exited.
Traceback (most recent call last):
File "P:\2020\09\25\bmi.py", line 52, in <module>
root = Root()
File "P:\2020\09\25\bmi.py", line 41, in __init__
COMMAND=self.weightget)
File "P:\Language\lib\tkinter\__init__.py", line 2345, in __getattr__
return getattr(self.tk, attr)
AttributeError: '_tkinter.tkapp' object has no attribute 'weightget'
Please help, thanks very much!
The indention of your function was wrong.
def weightget(self):
weight = self.weightEntry.get()
self.showWeight.configure(text=weight)
If you want this function working as class method and not as a normal function in your local namespace of your class. Which I assume, since you put the parameter self in the function, then you need to make sure its on the right spot by the indentation.
import tkinter as tk
class Root(tk.Tk):
def __init__(self):
super(Root, self).__init__()
#Info Bar
self.title("Shushu BMI Calculator")
self.geometry("1100x600")
#self.resizable("False")
#var
self.weight = tk.StringVar()
#self.w = tk.StringVar()
#Caption
self.caption = tk.Label(text = "BMI Calculator - Beta 2.0",
fg = "brown",
font="Arial 40")
self.caption.grid(column = 0, row = 0, sticky = "N")
#Copyright
self.copyright = tk.Label(text = "Powered by Shushu Studio",
fg = "green",
font = "Arial 20")
self.copyright.grid(column = 1, row = 0, sticky = "E")
#Weight input Row
self.weightInputTag = tk.Label(text="Please input your weight here (kg)")
self.weightInputTag.grid(column = 0, row = 1, sticky = "W")
self.weightEntry = tk.Entry(textvariable = self.weight)
self.weightEntry.grid(column = 0, row = 1)
self.weightSubmit = tk.Button(self,text="Submit",
command=self.weightget)
self.weightSubmit.grid(column = 0, row = 2)
self.showWeight = tk.Label(text="")
self.showWeight.grid(column = 0, row = 3)
def weightget(self):
weight = self.weightEntry.get()
self.showWeight.configure(text=weight)
root = Root()
root.mainloop()
from tkinter import *
import tkinter as tk
#object oriented BMI project
class Root(Tk):
def __init__(self):
super(Root, self).__init__()
def weightget(self):
weight = self.weightEntry.get()
self.showWeight.configure(text=weight)
#Info Bar
self.title("Shushu BMI Calculator")
self.geometry("1100x600")
#self.resizable("False")
#var
self.weight = tk.StringVar()
#self.w = tk.StringVar()
#Caption
self.caption = tk.Label(text = "BMI Calculator - Beta 2.0",
fg = "brown",
font="Arial 40")
self.caption.grid(column = 0, row = 0, sticky = "N")
#Copyright
self.copyright = tk.Label(text = "Powered by Shushu Studio",
fg = "green",
font = "Arial 20")
self.copyright.grid(column = 1, row = 0, sticky = "E")
#Weight input Row
self.weightInputTag = tk.Label(text="Please input your weight here (kg)")
self.weightInputTag.grid(column = 0, row = 1, sticky = "W")
self.weightEntry = tk.Entry(textvariable = self.weight)
self.weightEntry.grid(column = 0, row = 1)
self.weightSubmit = tk.Button(text="Submit", command=lambda:weightget(self))
self.weightSubmit.grid(column = 0, row = 2)
self.showWeight = tk.Label(text="")
self.showWeight.grid(column = 0, row = 3)
root = Root()
root.mainloop()
This works properly. Define the function before the process.
self.weightSubmit = tk.Button(text="Submit", command=lambda:weightget(self))
Give the command for the button like this as you are using object oriented programming. Make sure to use lambda
Read this https://www.w3schools.com/python/python_lambda.asp and you will get a better understanding about lambda

Python runs an int(x.get())/float(x.get()) command before the user can input anything into an entry [Python 3.6, Tkinter]

Title pretty much says it all, doing a project for school, there's an entry field that allows the user to input two values but it seems to run the float command before they can enter anything and gives an error. I have tried using int() instead and gives a base 10 error instead. I even tried moving the math section to another function thinking that it was trying to turn it into an int while creating the window.
Full error code:
File "main.py", line 111, in <module>
app = Application(root)
File "main.py", line 9, in __init__
self.height_and_weight()
File "main.py", line 29, in height_and_weight
weight = float(weightEntry.get())
ValueError: could not convert string to float:
My code:
from tkinter import *
class Application(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.grid()
self.height_and_weight()
def clear_window(self, option):
for widget in self.winfo_children():
if option == 1:
widget.grid_forget()
else:
widget.destroy()
def height_and_weight(self):
Label(self, text = "Enter your height in inches").grid(column = 0, sticky = W)
heightEntry = Entry(self)
heightEntry.grid(column = 0, sticky = W)
Label(self, text = "Enter your weight in pounds").grid(column = 0, sticky = W)
weightEntry = Entry(self)
weightEntry.grid(column = 0, sticky = W)
weight = float(weightEntry.get())
height = float(heightEntry.get())
weight *= .45
height *= .025
height **= 2
self.BMI = 10
self.BMI = weight / height
Button(self, text = "Continue", command = self.health_assessment).grid(column = 0, sticky = W)
def health_assessment(self):
self.clear_window(1)
if self.BMI < 18.5: # Underweight
Label(self, text = "You are underweight").grid(column = 0, sticky = W)
Label(self, text = "It is recommended that you gain some healthy weight.").grid(column = 0, sticky = W)
Label(self, text = "Would you like information on:").grid(column = 0, sticky = W)
choice = IntVar()
Radiobutton(self, text = "Building muscle mass", variable = choice, value = 1).grid(column = 0, sticky = W)
Radiobutton(self, text = "Increasing good calories in your diet", variable = choice, value = 2).grid(column = 0, sticky = W)
Radiobutton(self, text = "No thanks", variable = choice, value = 3).grid(column = 0, sticky = W)
if choice == 1:
link = "http://virtualfitnesstrainer.com/muscle-building/bodybuilding/how-to-gain-weight-and-muscle-%E2%80%93-even-if-you-are-under-weight/"
elif choice == 2:
link = "https://www.everydayhealth.com/weight/how-to-gain-healthy-weight.aspx"
else:
link = ""
Label(self, text = link).grid(column = 0, sticky = W)
Button(self, text = "EXIT").grid(column = 0, sticky = W)
elif self.BMI >= 18.5 and self.BMI < 25: # Normal weight
Label(self, text = "You are a normal weight.").grid(column = 0, sticky = W)
Label(self, text = "Great job staying healthy!").grid(column = 0, sticky = W)
Button(self, text = "EXIT", command = root.destroy()).grid(column = 0, sticky = W)
elif self.BMI >= 25 and self.BMI > 30: # Overweight
Label(self, text = "You are overweight.").grid(column = 0, sticky = W)
Label(self, text = "It is recommended that you shed a few pounds.").grid(column = 0, sticky = W)
Label(self, text = "Would you like information on:").grid(column = 0, sticky = W)
link = ""
if option:
link = "https://www.runtastic.com/blog/en/burn-more-calories-during-workout/"
else:
link = "https://www.healthline.com/nutrition/35-ways-to-cut-calories"
Label(self, text = link).grid(column = 0, sticky = W)
Button(self, text = "EXIT",command = root.destroy()).grid(column = 0, sticky = W)
else: # Obese
Label(self, text = "You are obese.").grid(column = 0, sticky = W)
Label(self, text = "You are at an unhealthy weight that increases your chances of health problems.").grid(column = 0, sticky = W)
Label(self, text = "Please select one of the following:").grid(column = 0, sticky = W)
link = ""
if option:
link = "https://www.runtastic.com/blog/en/burn-more-calories-during-workout/"
else:
link = "https://www.healthline.com/nutrition/35-ways-to-cut-calories"
Label(self, text = link).grid(column = 0, sticky = W)
if option or not option:
Button(self, text = "EXIT",command = root.destroy()).grid(column = 0, sticky = W)
root = Tk()
root.title("Health Assessment Program")
w = 500
h = 500
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
app = Application(root)
root.mainloop()
You're calling self.height_and_weight() (which then executes weight = float(weightEntry.get())) in Application.__init__, so it's executed here:
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
app = Application(root) # RIGHT HERE (and the error message tells you that)
root.mainloop()
So this is run before any Tkinter code. You should have a button that runs your function when pressed.

Python Tkinter: Loop The Computer's Turn A Certain Amount of Times

I'm writing a program for a dice game (Pig). In the game, the player will roll a d6 until they decide to hold their score (passing to the computer) or until they roll a 1, which will automatically make it the computer's turn.
The issue I'm having is that I need the function for the computer's turn to loop ten times. I want the computer to roll the die ten times, where it will either roll a one and pass back to the player or it will hold after ten rolls. How do I get the computer to roll the die ten times without using a loop inside of Tk?
Here's the code:
from Tkinter import *
from random import *
class App(Tk):
def __init__(self):
Tk.__init__(self)
self.headerFont = ("courier new", "16", "bold")
self.title("Pig, The Dice Game")
self.headers()
self.rollDie()
def headers(self):
Label(self, text = "Instructions", font = self.headerFont).grid(columnspan = 4)
Label(self, text = "Text", font = self.headerFont).grid(row = 1, columnspan = 4)
Label(self).grid(row = 1, columnspan = 4)
Label(self, text = "The Game of Pig", font = self.headerFont).grid(row = 2, columnspan = 4)
def rollDie(self):
self.btnRoll = Button(self, text = "Roll The Die")
self.btnRoll["state"] = 'active'
self.btnRoll.grid(row = 3, columnspan = 4)
self.btnRoll["command"] = self.playerTurn
self.btnHold = Button(self, text = "Hold")
self.btnHold["state"]= 'active'
self.btnHold.grid(row = 4, columnspan = 4)
self.btnHold["command"] = self.compTurn
self.btnPass = Button(self, text = "Pass")
self.btnPass.grid(row = 5, columnspan = 4)
self.btnPass["command"] = self.compTurn
Label(self, text = "You Rolled:").grid(row = 6, column = 0)
self.lblYouRolled = Label(self, bg = "#fff", anchor = "w", relief = "groove")
self.lblYouRolled.grid(row = 6, column = 1, columnspan = 1, sticky = "we")
Label(self, text = "Options:").grid(row = 7, column = 0)
self.lblOptions = Label(self, bg = "#fff", anchor = "w", relief = "groove")
self.lblOptions.grid(row = 7, column = 1, sticky = "we")
Label(self, text = "Player One Turn Score:").grid(row = 8, column = 0)
self.lblPlayerOneTurnScore = Label(self, bg = "#fff", anchor = "w", relief = "groove")
self.lblPlayerOneTurnScore.grid(row = 8, column = 1, sticky = "we")
def playerTurn(self):
self.oneTurnTotal = [0]
self.oneRoll = randint(1,6)
self.btnHold["state"] = 'active'
self.lblYouRolled["text"] = self.oneRoll
if self.oneRoll != 1:
self.oneTurnTotal.append(self.oneRoll)
self.lblOptions["text"] = "Roll again, or hold and pass the dice to Player Two."
else:
self.lblOptions["text"] = "You rolled a 1! Click 'Pass' to pass your turn to the computer."
self.oneTurnTotal = [0]
self.btnRoll["state"] = 'disabled'
self.btnHold["state"] = 'disabled'
def calculatePlayerOneTurnScore(self):
turnScore = sum(self.oneTurnTotal)
self.lblPlayerOneTurnScore["text"] = turnScore
def compTurn(self):
self.compTurnTotal = [0]
self.compRoll = randint(1,6)
self.lblYouRolled["text"] = self.compRoll
if self.compRoll != 1:
self.compTurnTotal.append(self.compRoll)
self.lblOptions["text"] = "The computer will roll again."
else:
self.lblOptions["text"] = "The computer rolled a 1! Its turn has ended."
self.compTurnTotal = [0]
self.btnRoll["state"] = 'active'
def calculatePlayerTwoTurnScore(self):
turnScore = sum(self.twoTurnTotal)
self.lblPlayerTwoTurnScore["text"] = turnScore
def main():
app = App()
app.mainloop()
if __name__ == "__main__":
main()
You could make the dicerolling a toplevel widget and then have your root "wait_window" for the rolling widget to complete. Create a function inside the toplevel widget that generates the roll and call it ten times
EXAMPLE
from Tkinter import *
yourscorevalue=12
cpuscorevalue=10
class dice:
def __init__(self,parent):
rollcount=0
top=self.top=Toplevel(parent)
while 1:
roll=self.diceroll()
rollcount+=1
if rollcount==10 or roll==1:
break
def diceroll(self):
#Random Dice Roll code
class dicegame:
def __init__(self):
self.root=Tk()
self.root.title('Dicerolling Game')
Label(self.root, text='Your Score').grid(column=0,row=0,sticky='ew')
Label(self.root, text=yourscorevalue, background='black',foreground='red').grid(column=1,row=0,sticky='ew')
Label(self.root, text='Computer Score').grid(column=0,row=1,sticky='ew')
Label(self.root, text=cpuscorevalue, background='black',foreground='red').grid(column=1,row=1,sticky='ew')
b=Button(self.root, text='Roll The Dice', command=self.roll).grid(column=0,row=2,sticky='ew')
c=Button(self.root, text="Done", command=self.root.destroy).grid(column=1,row=2,sticky='ew')
mainloop()
def roll(self):
d=dice(self.root)
self.root.wait_window(d.top)

Python - Tkinter empty window

I'm doing an assignment for a course and I'm not really sure what's up with the code but it runs without error, only displaying an empty window. I used an example given as a start and basically modified it to get this code. If needed I can provide the example code to compare.
from Tkinter import *
class App(Tk):
def __init(self):
Tk.__init__(self)
self.height()
self.weigh()
self.calculate()
self.output()
def height(self):
Label(self, text = "Enter Height, feet").grid()
self.feet = Entry(self)
self.feet.grid(row = 0, column = 1)
self.feet.insert(0, "100")
lblinches = Label(self, text = "Enter Height, inches")
lblinches.grid(row = 1, column = 0)
self.inches = Entry(self)
self.inches.grid(row = 1, column = 1)
def weigh(self):
Label(self, text = "Enter Weight").grid(row =2, column = 0)
self.weight = Entry(self)
self.weight.grid(row = 2, column = 1)
def output(self):
self.calcBMI = Button(self, text = "Calculate BMI")
self.calcBMI.grid()
self.calcBMI["command"] = self.calculate
Label(self, text = "Body Mass Index").grid(row = 4)
Label(self, text = "Status").grid(row = 5)
def calculate(self):
feet1 = int(self.feet.get())
inches1 = int(self.inches.get())
height1 = feet1 *12 + inches1
weight1 = int(self.weight.get())
bmi = (weight1 * 703) / (height1 * 2)
self.lblbmi["text"] = ".2f" % bmi
def main():
app = App()
app.mainloop()
main()
__init should be __init__. Since __init__ was not defined, none of the configuration methods were called.

TKinter process is not drawing Labels, Buttons, and Entry Fields... What am I doing wrong?

I'm a full time student, taking my first class in python.
This is so strange, it was working, and now, it is no longer showing the buttons, labels, and entry fields. I'm sure it was something I removed or added, but, I'm at a loss.
Any ideas? All suggestions are appreciated.
from Tkinter import *
import tkFont
import tkMessageBox
class BouncyGUI(Frame):
"""The GUI used to interface with the bouncy calculation from chapter 9 section 1."""
def __init__(self):
Frame.__init__(self)
# Establish the Base Frame
self.master.title("Calculate the Bounciness of a Ball")
self.master.rowconfigure(0, weight = 1)
self.master.columnconfigure(0, weight = 1)
self.master.grid()
self.master.resizable(0,0)
# Establish the components for capturing the Height
self._heightLabel = Label(self,
text = "Height of initial drop:",
justify = "left")
self._heightLabel.grid(row = 0, column = 0)
self._heightVar = DoubleVar()
self._heightEntry = Entry(self,
textvariable = self._heightVar,
justify = "center")
self._heightEntry.grid(row = 0, column = 1)
# Establish the "bounciness index"
self._bouncyIndex = Label(self,
text = "Bounciness Index:",
justify = "left")
self._bouncyIndex.grid(row = 1, column = 0)
self._bouncyVar = DoubleVar()
self._bouncyEntry = Entry(self,
textvariable = self._bouncyVar,
justify = "center")
self._bouncyEntry.grid(row = 1, column = 1)
self._bouncyVar.set(0.6)
# Establish number of allowable bounces
self._numberBounces = Label(self,
text = "Number of Bounces:",
justify = "left")
self._numberBounces.grid(row = 2, column = 0)
self._numberBouncesVar = IntVar()
self._numberBouncesEntry = Entry(self,
textvariable = self._numberBouncesVar,
justify = "center")
self._numberBouncesEntry.grid(row = 2, column = 1)
# Establish a field for the response
self._answer = Label(self,
text = "Distance Travelled",
justify = "left")
self._answer.grid(row = 3, column = 0)
self._answerVar = DoubleVar()
self._answerFont = tkFont.Font(weight="bold", size = 12)
self._answerEntry = Entry(self,
textvariable = self._answerVar,
justify = "center",
font = self._answerFont)
self._answerEntry.grid(row = 3, column = 1)
self._answerEntry.config(state = DISABLED, bg = "green")
# Create frame to hold buttons
self._buttonFrame = Frame(self)
self._buttonFrame.grid(row = 4, column = 0, columnspan = 2)
# Create Reset Button
self._buttonReset = Button(self._buttonFrame,
text = "Reset",
command = self._reset,
width = 15,
padx = 2,
pady = 2)
self._buttonReset.grid(row = 0, column = 0)
#self._buttonReset.config(state = DISABLED)
# Create Calculate Button
self._buttonCalc = Button(self._buttonFrame,
text = "Calculate",
command = self._calculate,
width = 15,
padx = 2,
pady = 2)
self._buttonCalc.grid(row = 0, column = 1)
#self._buttonCalc.config(state = NORMAL)
def _reset(self):
"""Allow for the screen to reset for fresh data entry."""
self._heightVar.set(0.0)
self._numberBouncesVar.set(0)
self._answerVar.set(0.0)
#self._buttonCalc.config(state = NORMAL)
#self._buttonReset.config(state = DISABLED)
#self._numberBouncesEntry.config(state = NORMAL)
#self._bouncyEntry.config(state = NORMAL)
#self._heightEntry.config(state = NORMAL)
def _calculate(self):
"""Calculate the bounciness and update the GUI"""
if self._validDataTypes():
self._answerVar.set(computeDistance(self._heightVar.get(), \
self._bouncyVar.get(), \
self._numberBouncesVar.get()))
#self._numberBouncesEntry.config(state = DISABLED)
#self._bouncyEntry.config(state = DISABLED)
#self._heightEntry.config(state = DISABLED)
#self._buttonCalc.config(state = DISABLED)
#self._buttonReset.config(state = NORMAL)
def _validDataTypes(self):
theMessage = ""
if self._isInt(self._numberBouncesVar.get()) != True:
theMessage += "Please re-enter Integer Value for Number of Bounces.\n"
elif self._isFloat(self._bouncyVar.get()) != True:
theMessage += "Please re-enter Float Value for Bounciness Index.\n"
elif self._isFloat(self._heightVar.get()) != True:
theMessage += "Please re-enter Float Value for Initial Height."
if len(message) > 0:
tkMessageBox.showerror(message = message, parent = self)
return False
else:
return True
def _isInt(self, value):
# Test to ensure that value entered is an integer
try:
x = int(value)
except ValueError:
# If not return false
return False
# if it is an integer, return true
return True
def _isFloat(self, value):
# Test to ensure that value entered is a float value
try:
x = float(value)
except ValueError:
# If not return false
return False
# If it is a float, return true
return True
def computeDistance(height, index, bounces):
"""Compute the distance travelled."""
total = 0
for x in range(bounces):
total += height
height *= index
total += height
return total
def main():
"""Run the main program"""
BouncyGUI().mainloop()
main()
Your main() function setup code isn't working properly. I'm not sure how you had it set up before, but one way to get it working is this:
def main():
"""Run the main program"""
root = Tk()
gui = BouncyGUI()
gui.pack()
root.mainloop()
You need to grid the main app, not just call its mainloop:
def main()
app = BouncyGUI()
app.grid()
app.mainloop()
there is an error in your code when compiling:
NameError: global name 'message' is not defined

Categories