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.
Related
I currently have a very simple tkinter app which prints the given text in the console with no issues. However I want a set of numbers (1, 2, 3, 4, 5, 6) to add 1 to another float (which in this case is the count, for anyone that counts cards in blackjack). I just can't seem to get it to work, though.
Here is my current code:
master = Tk()
e = Entry(master)
e.pack()
plusOne = [1, 2, 3, 4, 5, 6]
count = 0
e.focus_set()
def callback():
print(e.get())
print("-------")
if e.get() in plusOne:
count + 1
print(count)
b = Button(master, text = "OK", width = 10, command = callback)
b.pack()
mainloop()
However this just prints the number which was put into the text box. It would be useful to see which cards were played by just seeing user inputs and then the count printed underneath it.
Would anyone know how to help?
You need to declare the input as an integer in this case since that is what you put into your list. Otherwise I believe the entry value will be viewed as a string. I modified the script to work, but I'm not sure the count + 1 is going to do what you want for card counting purposes. You would need a running count to go + or - to count face cards successfully. Hopefully this helps.
import tkinter as tk
plusOne = [1, 2, 3, 4, 5, 6] # these are integers
def callback():
value = int(entry_field.get()) # sets entry to match int from list set up
entry_field.delete("0", tk.END)
count = 0
if value in plusOne:
print(count + 1)
root = tk.Tk()
entry_field = tk.Entry(root, width=20)
entry_field.pack()
button = tk.Button(root, text = "OK", width = 10, command= callback)
button.pack()
root.mainloop()
Here is a much easier and straight forward way to achieve the result without making a GUI.
plusOne = [1, 2, 3, 4, 5, 6] # values for non face cards
minusOne = [10]# value for face cards
nothing = ""
count = 0
while True:
try:
value = int(input("Enter Value:"))
if value != nothing and value in plusOne: # make sure the entry isn't left blank
count += 1 # add to the count by value of 1
print("The count is now:", count)
elif value in minusOne:
count -= 1 # reduce the count by a vlue of 1
print("The count is now:", count)
except:
print("Value not an integer")# raises error for non integer
A quick idea for if you want to keep the GUI would maybe be like this:
import tkinter as tk
plus_count = [1, 2, 3, 4, 5, 6]
minus_count = [10]
var = [0]
nothing = ""
def count_cards():
value = int(entry_field.get())
entry_field.delete("0", tk.END)
if value != nothing and value in plus_count:
for item in var:
if item != nothing:
add_count = item + 1
var.pop()
var.append(add_count)
print("The count is:", var)
elif value != nothing and value in minus_count:
for item in var:
if item != nothing:
subtract_count = item - 1
var.pop()
var.append(subtract_count)
print("The count is:", var)
root = tk.Tk()
entry_field = tk.Entry(root, width=15, textvariable=tk.StringVar())
entry_field.pack()
button = tk.Button(root, text="Count", command= count_cards)
button.pack()
root.mainloop()
code is running good in main project , took some sample code from that as below
from tkinter import *
root = Tk()
root.geometry('200x200')
root.title('Testing')
num1 = StringVar()
num2 = StringVar()
def callback(integer):
if integer.isdigit():
return True
elif integer == "":
return True
else:
return False
def limit_no1(no):
c = no.get()[0:16]
no.set(c)
num1.trace("w", lambda name, index, mode, sv=num1: limit_no1(sv))
reg = root.register(callback)
ent1 = Entry(root, textvariable=num1)
ent1.pack()
ent1.config(validate="key", validatecommand=(reg, '%P'))
this has some condition as accepting only numbers and up 16 digits
but as like some web apps i need spacing after 4 characters
is there any method for that so that i can apply to this and and for input of currency also as ',' in btw data
I worked on some code but indexing getting issue in indexing
the below code continuation of above only
num2.trace("w", lambda name, index, mode, sv=num2: limit_no2(sv))
ent2 = Entry(root, textvariable=num2)
ent2.pack(pady=20)
ent2.config(validate="key", validatecommand=(reg, '%P'))
def limit_no2(no):
c = no.get()[0:19]
split_string = [c[i:i + 4] for i in range(0, len(c), 4)]
if len(split_string) > 1:
final_string = ''
for i in range(len(split_string)):
final_string += split_string[i]
final_string += " "
no.set(final_string)
else:
no.set(c)
root.mainloop()
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.
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