When I try to run this code, a ValueError appears alluding to the function numRandom. I though Python could pass a string representation of a int to an int.
import tkinter
import random
window = tkinter.Tk()
window.geometry('600x500')
x = random.randint(1,300)
remainingTime = True
Attempts = 4
def numRamdom():
global Attempts
while Attempts > 0:
numWritten = int(entryWriteNumber.get())
if numWritten > x:
lblClue.configure(text = 'Its a bigger number')
Attempts = Attempts -1
if numWritten < x:
lblClue.configure(text = 'Its a smaller number')
Attempts = Attempts -1
if numWritten == x:
lblClue.configure(text = 'Congratulations ;)')
remainingTime = False
return remainingTime, countdown(0)
if Attempts == 0:
remainingTime = False
return remainingTime, countdown(0), Attempts, gameOver()
entryWriteNumber = tkinter.Entry(window)
entryWriteNumber.grid(column = 0, row = 1, padx = 10, pady = 10)
numRamdom()
window.mainloop()
The problem is because when the code is ran, it directly calls numRamdom(), that is, initially the entry widgets are empty, and they run it with those empty entry widget and hence the error. So just assign a button and a command, like:
b = tkinter.Button(root,text='Click me',command=numRamdom)
b.grid(row=1,column=0)
Make sure to say this before the mainloop() after the def numRamdom():. The button just runs the function only when the button is clicked.
Or if you want button-less then try:
METHOD-1:
root.after(5000,numRamdom) #after 5 sec it will execute function
But keep in mind, if the user doesn't enter properly in 5 sec then some error would pop up.
METHOD-2:
def numRamdom(event):
......
entryWriteNumber.bind('<Return>',numRamdom)
This is so that, if you press enter key in the entry widget(after entering data) it will run the function.
Hope this helps, do let me know if any errors.
Cheers
Here's a fully working example based on your code. Your problem was trying to convert the contents of the Entry before anything was inside of it. To fix this problem, you can add a button which calls the command numRamdom()
import tkinter
import random
window = tkinter.Tk()
window.geometry('600x500')
x = random.randint(1,300)
remainingTime = True
Attempts = 4
def numRamdom():
global Attempts, lblClue, x
if Attempts > 0:
numWritten = int(entryWriteNumber.get())
if numWritten < x:
lblClue.configure(text = 'Its a bigger number')
Attempts = Attempts -1
elif numWritten > x:
lblClue.configure(text = 'Its a smaller number')
Attempts = Attempts -1
else:
lblClue.configure(text = 'Congratulations ;)')
remainingTime = False
#return remainingTime, countdown(0)
if Attempts == 0:
remainingTime = False
#return remainingTime, countdown(0), Attempts, gameOver()
else:
lblClue.configure(text = "You ran out of attempts!")
entryWriteNumber = tkinter.Entry(window)
entryWriteNumber.grid(column = 0, row = 1, padx = 10, pady = 10)
entryWriteButton = tkinter.Button(window, text = "Push me!", command = numRamdom)
entryWriteButton.grid(column = 1, row = 1)
lblClue = tkinter.Label(window)
lblClue.grid(row = 2, column = 1)
window.mainloop()
You'll still get an error if the value passed is not able to be converted into an integer, but that's easy to fix with an if statement.
Related
the get age function needs y
import math
import os
from tkinter import *
root = Tk()
root.title("DOG AGE CALCULATOR!!")
#define function to convert x.0 to x
def formatNumber(num):
if num % 1 == 0:
return int(num)
else:
return num
#print menu
def getAge():
# Convert y
if(y == 1):
dy = int(15)
elif(y == 2):
dy = int(24)
elif(y > 2):
dy = int(((y-2)*5)+24)
else:
p = 2
#convert m
if(y == 0):
dm = float(m*1.25)
elif(y == 1):
dm = float(m*0.75)
elif(y > 1):
dm = float(m*(5/12))
else:
p = 2
#add excess months to years
if(dm > 12):
dm = dm//12
y = y+(dm%12)
#add dog years and months
dogym = float(dy+dm)
#seperate dog month and year
dogmonth, dogyears = math.modf(dogym)
dogmonths = dogmonth*12
#formatting dog year and month
dogmonths = formatNumber(dogmonths)
dogyears = formatNumber(dogyears)
dogyearstr = str("{} Dog Years".format(dogyears))
dogmonthstr = str("{} Dog Months".format(dogmonths))
for widget in frame.winfo_children():
widget.destroy()
ylabel = Label(root, text=dogyearstr)
mlabel = Label(root, text=dogmonthstr)
ylabel.pack()
mlabel.pack()
title = Label(root, text="\/\/\!!DOG AGE CALCULATOR!!\/\/\\")
yentry = Entry(root)
mentry = Entry(root)
getagebutton = Button(root, text="Get Dog Age", command=getAge)
yentry.insert(0, "Dog's Age In Years")
mentry.insert(0, "Dog's Age In Months")
title.pack()
yentry.pack()
mentry.pack()
getagebutton.pack()
y = yentry.get()
m = mentry.get()
In this program, how do i fix the error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\name\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 1948, in __call__
return self.func(*args)
^^^^^^^^^^^^^^^^
File "C:\Users\name\PycharmProjects\DAC\maintmp.py", line 19, in getAge
if(y == 1):
^
UnboundLocalError: cannot access local variable 'y' where it is not associated with a value
(the file is maintmp.py)
You should move the call to y = yentry.get() inside the getAge() function
def getAge():
y = yentry.get()
# Convert y
if(y == 1):
dy = int(15)
elif(y == 2):
dy = int(24)
elif(y > 2):
dy = int(((y-2)*5)+24)
else:
p = 2
... # code omitted for brevity
You'll want to do a similar thing when getting the value of m. This way, the values are fetched from the entries when they're needed and can be updated accordingly.
As it's currently written, you're calling get() on your Entry widgets immediately after declaring them, so y and m will both be equal to None
You're getting the error UnboundLocalError: cannot access local variable 'y' where it is not associated with a value because you're trying to perform a comparison operation on y before it has any value (as far as getAge is concerned)
Also, unrelated to the error: the explicit conversions like int(15) are unnecessary. 15 is already an integer. You can just do dy = 15, dy = 24, etc. Since y is a string, you can just do the conversion on y with y = int(yentry.get()) (the same goes for m).
Then you don't need to worry about things like float(m*1.25) either, since any number multiplied by a float will return a float!
I'm new to programming and I'm trying to make an app that calculates the smallest common for you, but for some reason whenever i run it, tkinter seems to just freeze and i don't know what the error seems to be. I suspect that it's the myLabel part, since I can still read the result inside the Terminal.
Thanks in advance~
from tkinter import *
root = Tk()
root.title("I can find the smallest common, unless you enter letters... I'm dyslexic.")
numbers_list = []
global numbers
numbers = Entry(root, width = 10, borderwidth = 5, state = DISABLED)
numbers.pack()
numbers.insert(0, "")
#
def button_click():
#each gets a button
get_smallest_common = Button(root, text = 'Confirm your number!'
, command = smallest_common)
get_smallest_common.pack()
get_smallest_common = Button(root, text = 'Undo!'
, command = lambda: undo())
get_smallest_common.pack()
get_smallest_common = Button(root, text = 'Start the search!'
, command = lambda: find_the_s_common())
get_smallest_common.pack()
#disable the start button
def switch():
myButton['state'] = DISABLED
#configure helps bringing a disabled thing back to normal state
numbers.configure(state = "normal")
def smallest_common():
#add to the list for late use
numbers_list.append(numbers.get())
print(numbers_list)
numbers.delete(0, END)
def undo():
#add to the list for late use
numbers_list.pop()
print(numbers_list)
numbers.delete(0, END)
def find_the_s_common():
process_list = []
condition = True
x = 0
while condition:
#the multiplication keep rising till count is 3
a = int(x) + 1
x = a
#loop to multiply the number with x + 1
for number in numbers_list:
y = int(number) * int(a)
process_list.append(y)
#check whether the result has been added to append into list
if y in process_list:
#check whether the list contains two duplicates to
if process_list.count(y) == 3:
condition = False
result = 'The number is ' + str(y) + '!'
print(result)
else:
continue
else:
continue
myLabel = Label(root, text = result)
myLabel.pack()
#combine the two function for myButton
def button_click_switch():
button_click()
switch()
myButton = Button(root, text = 'Click me to start'
, command = lambda: [button_click(), switch()])
myButton.pack()
root.mainloop()
Most probably, you have problem if the numbers entered is less than 3. As a result, one simple way is to decrease the condition to 2 and if a single number is entered the result is the number itself, if 2 or more no freezing.
NOTE: Freezing here is actually, while loop is running as condition is always True, because of process_list.count(y) == 3 will always be False if less than 3 number entered.
See my suggestion:
from tkinter import *
root = Tk()
root.title("I can find the smallest common, unless you enter letters... I'm dyslexic.")
numbers_list = []
global numbers
numbers = Entry(root, width = 10, borderwidth = 5, state = DISABLED)
numbers.pack()
numbers.insert(0, "")
#
def button_click():
#each gets a button
get_smallest_common = Button(root, text = 'Confirm your number!', command = smallest_common)
get_smallest_common.pack()
get_smallest_common = Button(root, text = 'Undo!', command = lambda: undo())
get_smallest_common.pack()
get_smallest_common = Button(root, text = 'Start the search!' , command = lambda: find_the_s_common())
get_smallest_common.pack()
#disable the start button
def switch():
myButton['state'] = DISABLED
#configure helps bringing a disabled thing back to normal state
numbers.configure(state = "normal")
def smallest_common():
#add to the list for late use
numbers_list.append(numbers.get())
print(numbers_list)
numbers.delete(0, END)
def undo():
#add to the list for late use
numbers_list.pop()
print(numbers_list)
numbers.delete(0, END)
def find_the_s_common():
process_list = []
condition = True
x = 0
if len(numbers_list) == 1: # RETURN IF THE LIST HAS A SINGLE VALUE
result = 'The number is ' + str(numbers_list[0]) + '!'
else:
while condition:
#the multiplication keep rising till count is 3
a = int(x) + 1
x = a
#loop to multiply the number with x + 1
for number in numbers_list:
y = int(number) * int(a)
process_list.append(y)
#check whether the result has been added to append into list
if y in process_list:
#check whether the list contains two duplicates to
if process_list.count(y) == 2: # DECREASE THE CONDITIONS TO 2
condition = False
result = 'The number is ' + str(y) + '!'
print(result)
else:
continue
else:
continue
myLabel = Label(root, text = result)
myLabel.pack()
#combine the two function for myButton
def button_click_switch():
button_click()
switch()
myButton = Button(root, text = 'Click me to start', command = lambda: [button_click(), switch()])
myButton.pack()
root.mainloop()
Suggestion to add two conditons;
(1) create a condition until at least 1 number is entered! if len(numbers_list) == 0, loop to enter a number.
(2) create a condition, until N number is added, let's say user must enter at least 3 numbers, change process_list.count(y) == 3 to process_list.count(y) == N and add condition if len(numbers_list) != N, loop to enter more numbers.
In my Tkinter application, I have three special entry widgets Serial Number, x, y that I need to modify as follow:
Only a maximum of 4 digits can be entered in serial number (sn) entry
The entry y is disabled and its value is equal to the entry x if sn is empty.
The user can enter a random input in y, if sn is not empty
So far I was only able to implement the first point, with the help of validate command option. Does someone of you have an idea of how the 2) and 3) points can also be implemented with the help of validate command?
from tkinter import *
root = Tk()
label_serial_number = Label(root, text = "Serial Number:")
label_x = Label(root, text = "Enter Value for x:")
label_y = Label(root, text = "Enter value for y:")
entry_serial_number = Entry(root)
entry_x = Entry(root)
entry_y = Entry(root)
# Display widgets
label_serial_number.grid(row = 0, column = 0, sticky = "W")
label_x.grid(row = 1, column = 0)
label_y.grid(row = 2, column = 0)
entry_serial_number.grid(row = 0, column = 1)
entry_x.grid(row = 1, column = 1)
entry_y.grid(row = 2, column = 1)
# 1) Part: - only digits can be entered in the series label - only 4 digits are allowed to enter
def only_numeric_input(P):
if len(P) > 4:
return False
# checks if entry's value is an integer or empty and returns an appropriate boolean
if P.isdigit() or P == "": # if a digit was entered or nothing was entered
return True
return False
callback = root.register(only_numeric_input) # registers a Tcl to Python callback
entry_serial_number.configure(validate="key", validatecommand=(callback, "%P")) # enables validation
mainloop()
For item 2 and 3, first create a StringVar for both the x and y entries:
var_x = StringVar()
entry_x = Entry(root, textvariable=var_x)
entry_y = Entry(root, textvariable=var_x, state='disabled') # initial disabled
Then you can add some logic inside the validate function:
def only_numeric_input(P):
if len(P) > 0:
# enable entry_y and unlink its content from entry_x
entry_y.config(textvariable='', state='normal')
else:
# disable entry_y and link its content with entry_x
entry_y.config(textvariable=var_x, state='disabled')
if len(P) > 4:
return False
# checks if entry's value is an integer or empty and returns an appropriate boolean
if P.isdigit() or P == "": # if a digit was entered or nothing was entered
return True
return False
I have a project, that currently will only ask 1 question and then break, giving me the message:
IndexError: list index out of range
the error is on line 42 which is:
label.config(text=question[q]).
Here is the code:
from tkinter import *
import tkinter as tk
q = -1
count = 0
correct = 0
incorrect = 0
question=["File compression software is an example of.. software", "Each piece of hardware e.g printer, monitor, keyboard, will need an up to date... installed", "application softwares control the computer, true or false?"]
answer = ["utility", "driver", "false"]
answer_cap = ["Utility","Driver","False"]
root = Tk()
name = tk.Label(root,text = "Computing quiz")
name.pack()
label = tk.Label(root,text = question[0])
label.pack()
entry = tk.Entry(root)
entry.pack()
def out():
global q,correct,incorrect,count
while count < len(question):
ans = entry.get()
if answer[q] == ans or answer_cap[q] == ans :
q+=1
entry.delete(0, END)
correct+=1
print(correct)
label.config(text=question[q])
else:
q+=1
entry.delete(0, END)
incorrect+=1
print(incorrect)
label.config(text=question[q])
entry.delete(0, END)
label.config(text = "Correct: "+str(correct) + " Incorrect: "+str(incorrect))
print(correct)
def stop():
global q,correct,incorrect
q = 0
correct = 0
incorrect = 0
entry.delete(0, END)
label.config(text = question[0])
button = tk.Button(root,text = "Submit",command = out)
button.pack()
button_two = tk.Button(root,text = "Restart",command = stop)
button_two.pack()
Look at your while loop. You are doing something while count < ..., but inside the loop count is not updated, but q is. Because of this q will be very very big soon, so it will be much higher then the len(question). No wonder the IndexError
You have to correct that loop, because even if you deal with the IndexError the while loop will run forever.
A workaround (I do not suggest this, in my opinion you should just correct the whole while loop) could be to except the IndexError and break out of the loop
I need help understanding how I can use the checkbox I've made turn a part of the program off when checked on and turn another part off when the checkbox is off. My idea is that when the checkbox is on, I want the addPercTip(self) section to be turned on and the addRateTip to be turned off, and vice-versa when the checkbox is off. PercTip off and RateTip on. My problem right now is that in my calculations, it is trying to take info from both parts, so one of them needs to be off. Any help would be enormously appreciated!
from Tkinter import *
class App(Tk):
def __init__(self):
Tk.__init__(self)
self.headerFont = ("Times", "16", "italic")
self.title("Restaurant Tipper")
self.addOrigBill()
self.addChooseOne()
self.addPercTip()
self.addRateTip()
self.addOutput()
def addChooseOne(self):
Label(self, text = "Check ON for % check OFF for rating!",
font = self.headerFont).grid(row = 2, column = 1)
self.checkVar = IntVar()
self.chkCheck = Checkbutton(self, variable = self.checkVar)
self.chkCheck.grid(row = 3, column = 1)
def calculate(self):
bill = float(self.txtBillAmount.get())
percTip = self.percVar
rateTip = int(self.scrScale.get())
tip = bill * percTip
self.lblTip["text"] = "%.2f" % tip
totalBill = tip + bill
self.lblTotalBill["text"] = "%.2f" % totalBill
if rateTip <= 2:
percTip = .10
elif 3 <= rateTip <= 4:
percTip = .12
elif 5 <= rateTip <= 6:
percTip = .15
elif 7 <= rateTip <= 8:
percTip = .17
elif 9 <= rateTip <= 10:
percTip = .20
else:
self.lblTotalBill["text"] = "Something is wrong"
def main():
app = App()
app.mainloop()
if __name__ == "__main__":
main()
When you instantiate a checkbutton you can set a command attribute. This is a function that will be called whenever the button is checked.
self.chkCheck(self, variable = self.checkVar, command = doStuff)
def doStuff(self)
print 'doing stuff'
EDIT:
As to the comment below:
def doStuff(self):
if self.checkVar.get() == 1: <<<1 is the 'checked value'
percTip = True
rateTip = False
However, you don't actually need to do that. In your calculate() function you could simply call self.checkVar.get() and if it is 1 then evaluate and if 0 (unchecked) then evaluate differently etc.