how to fix my Error handling code? (tkinter GUI) - python

I have split the error handing into 3 parts, ( check_black, raise_error, delete_error)
About about the functions:
the check_blank() function checks if there are any errors in the input
entries and raise_error() function raises the error by gridding() a
ErrorLabel. and if the error have been resolved then delete_error()
function deletes the error label.
(there are 5 entry boxes and 4 check buttons, and a 'done' button)
( error should be raised if there's no input for all 5 Entries or at least one check button hasn't been checked )
this is the check_blanks() function:
def checkblanks(self):
flag = 0
if not self.Text1.get(): #text.get() and Answer1.get() etc stores input from entry so if there's no entry then it will be empty
flag = 1
if not self.Answer1.get():
flag = 1
if not self.Answer2.get():
flag = 1
if not self.Answer3.get():
flag = 1
if not self.Answer4.get():
flag = 1
if not self.var.get(): # var.get stores input from check button so if its not checked then there won't be anything stored in var.get()
flag += 2
if flag == 0: # flag = 0 means no error
self.ErrorLabel = None
self.add() #### EDIT ####
self.delete_error()
elif flag == 1 or flag == 2 or flag == 3: # if flag is 1 or 2 or 3 means there is error
self.raise_error(flag)
flag 0 = means no errors
flag 1 = means that there's no input in all 5 entries
flag 2 = means at least one check button hasn't been checked
flag 3 = means both above errors occurred
this is the raise error_function:
def raise_errors(self, flag):
if flag == 1 or flag == 3:
self.L5.grid_forget()
self.ErrorLabel = tk.Label(self.frame2, text="Error: Fill all the blanks !", fg='white', bg='red')
self.ErrorLabel.grid(row=7, column=0, pady=10)
elif flag == 2:
self.L5.grid_forget()
self.ErrorLabel = tk.Label(self.frame2, text="Error: check ✔️ the correct answer ", fg='white', bg='red')
self.ErrorLabel.grid(row=7, column=0, pady=10)
and the delete_error function:
def delete_error(self):
if self.ErrorLabel is not None: # checks if the error label exists
self.ErrorLabel.grid_forget()
but there is a problem:
When the error is raised and then error label is made; after the
errors are resolved then the error label is not deleted by
delete_error()
and sometimes multiple error labels overlap each other and it not very
efficient
I need to make the error handling functions more simple and work
properly.
EDIT:
also the function add() is called if flag == 0,( if there's no errors
) the add() function just creates a new frame
with the same entries and check buttons its and checks for errors all
over again.
its just a repeat loop
this is that function:
def add(self):
self.X += 1
self.frame2.grid_forget() # deleted main frame
self.amount_of_questions -= 1
self.question(self.X) # question() creates new frame with same widgets

It is over writing each label because you are creating new label for each function call and so on, so I think its safe for us now, to get rid of None and try to use config:
def checkblanks(self):
flag = 0
.....
self.ErrorLabel = tk.Label(self.frame2,fg='white',bg='red') # Define the variable with basic base options
if flag == 0:
self.delete_error()
elif flag == 1 or flag == 2 or flag == 3:
self.raise_error(flag)
and then delete_error() would be:
def delete_error(self):
self.ErrorLabel.grid_forget() # Now always errorlabel is defined, you might want to use winfo_exists
So now you have to use config to update the widget inside raise_errors():
def raise_errors(self, flag):
if flag == 1 or flag == 3:
self.L5.grid_forget()
self.ErrorLabel.config(text="Error: Fill all the blanks !") # Update the widget
self.ErrorLabel.grid(row=7, column=0, pady=10) # Grid it
elif flag == 2:
self.L5.grid_forget()
self.ErrorLabel.config(text="Error: check ✔️ the correct answer ") # Update the widget
self.ErrorLabel.grid(row=7, column=0, pady=10) # Grid it
Since I don't have a code to test this up with, this is based on imagination, I think you need winfo_exists inside delete_errors() too.
after the errors are resolved then the error label is not deleted by delete_error()
This might be due to the way self.ErrorLabel was defined as None. Now that it is always defined as a Label, it should be fine.
EDIT: Can you try moving the label inside of __init__:
def __init__(self):
....
self.ErrorLabel = tk.Label(self.frame2,fg='white',bg='red')

Related

a value in a radiobutton on tkinter doesn't work

I used this program for few weeks and it worked perfectly. Now, without changing anything, it doesn't work. More precisely, the orientation value doesn't change when you click on the radiobutton. Then, the program PosChoisie return 0 instead of either 1 or 2.
I'm on this program for 2 days, but even if I tried hard, I didn't found the error. Thanks for your futur help.
value=StringVar()
orientation = IntVar()
radiobutton_Horizontal = Radiobutton(fen, text="Horizontal", variable=orientation, value=1).pack()
radiobutton_Vertical = Radiobutton(fen, text="Vertical", variable=orientation, value=2).pack()
def PosChoisies():
L=[]
ori=IntVar()
ori = orientation.get()
if ori == 1:
o='horizontal'
L.append(o)
#print('horizontal')
elif ori == 2:
o='vertical'
L.append(o)
#print('vertical')
print(L)
print(ori)
return L
butValider = Button(fen, text="valider", relief = RAISED, command=lambda:(print(abs,ord,o)).pack()
fen.mainloop() ```

How to fix the game function?

im beginner on python and as a practice i want to solve this ( https://www.practicepython.org/exercise/2014/07/05/18-cows-and-bulls.html ) by tkinter
when i run this code and press start button it hangs and no error is shown in pycharm, even when i debug
obviously the bug is in game code
can you help me with this?
from tkinter import *
import random
def entry_box():
global user_guess
start_button.destroy()
user_guess=Entry(win,font='Bradly 12', width=25)
user_guess.insert(END,'0000')
user_guess.place(x=150,y=150)
game()
def game():
global user_guess , result
digit=[]
num =[]
counter = 0
for i in range(4):
digit.append(random.randint(0,9))
while num != digit:
num = list(user_guess.get())
cow = 0
bull = 0
for i in range(4):
if int(num[i]) in digit:
if int(num[i])==digit[i]:
cow += 1
else:
bull += 1
counter += 1
result.set('cow = %d \n bull = %d'%(cow,bull))
result.set('WELL DONE! YOU FOUND IT AFTER %d GUESS ' %counter )
win = Tk()
win.title('Let\'s play')
frame = Frame(win, height=300, width=500, bg='lightblue')
frame.pack()
result = StringVar()
result.set('cow=0\nbull=0')
start_button = Button(win , text='start', font='Broadway 15',command = entry_box)
start_button.place(x=200, y=175)
results = Label(win, textvariable=result, font='Broadway 20',bg='lightblue', fg='darkblue')
results.place(x=200 , y=0)
win.mainloop()
Your code hangs because of multiple reasons:
as #furas mentioned, num != digit will always be False, because you compare list of chars with list of digits;
Even if you fix this, your code will just never exit the loop: you will compare the first list [0,0,0,0] with the random one (num) and unless they are equal, you will get False. Then the code takes the same two lists, and compares them infinitely, with always the same outcome. You can see this easily if you add a print statement in the while loop.
This is one possible solution:
import tkinter as tk
import random
class MainGame(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.main_frame = tk.Frame(self, height=300, width=500, bg='lightblue')
self.main_frame.pack()
self.result = tk.StringVar()
self.result.set("Cow=0\nBull=0")
self.start_button = tk.Button(self.main_frame, text='start', font='Broadway 15', command=self.entry_box)
self.start_button.place(x=200, y=175)
self.results = tk.Label(self.main_frame, textvariable=self.result, font='Broadway 20', bg='lightblue',
fg='darkblue')
self.results.place(x=200, y=0)
def entry_box(self):
self.start_button.destroy()
self.user_guess = tk.Entry(self.main_frame, font='Bradly 12', width=25)
self.user_guess.insert(tk.END, '0000')
self.user_guess.place(x=150, y=150)
self.start_game()
def start_game(self):
user_input = self.user_guess.get()
num = [int(cypher) for cypher in user_input]
counter = 0
game_playing = True
while game_playing is True:
digit = [random.randint(0, 9) for i in range(4)]
cow, bull = 0, 0
for i in range(4):
if num[i] in digit:
if num[i] == digit[i]:
cow += 1
else:
bull += 1
counter += 1
print("Turn {}: cows = {}\t bulls={}".format(counter, cow, bull))
if cow == 4:
print("digit = {}\t num = {}".format(digit, num))
game_playing = False
if __name__ == "__main__":
game = MainGame()
game.mainloop()
First thing: do not use global imports (from tkinter import *). Instead use import tkinter as tk.
Then let's look at your entry_box: the function as you defined it takes no argument, but then you expect it to delete the start_button: the only reason this works is because the function is defined in the same script, but as soon as you move it to another script for example, it will fail. You did the same with result, which is defined in the main body, but then used in game, and for the win variable used to set the user_guess Entry widget.
The solution for this is to 1) reformat your code to account for these changes, which can work for something this small 2) use global variables, but this is usually considered a bad practice, because as your code grows it becomes a pain to track them down (plus many other reasons) 3) use classes, which is what I did here.
So here is what I did: I create a class, and in the __init__ I put the things I want to have available when the script starts, or that I generally want to use throughout the game: the main frame where I will place the widgets, the results or the start button.
Then the entry_box function: You see that I pass just self: since the start button was defined as self.start_button in the __init__, there is no reason to pass it as an argument, because it is already stored in self as an attribute. Same with the main_frame where I put the Entry widget.
Lastly the game function: here, I make sure that the comparison between num and digit is between int numbers. Then if the comparison fails, I draw another random list of 4 elements for digit and repeat. The results are printed in the terminal.
This is by no means perfect, and you can easily improve it in a few ways:
1) the comparison between the lists can be easily made faster and shorter with numpy;
2) I did not update the results widget. You should be able to do it with what I told you here.
3) I assume you want the user to input the user_guess. You just have to modify a bit this code
Hope it helps!

Python Tkinter validation command not working after deleting entry

In my program, the entry widget no longer validates after the delete command has been used on it - the idea is that if it meets a certain requirement, the text in the box is automatically deleted but continues to validate the input.
from tkinter import *
TEXT_TO_MATCH = 'APPLE'
def validate(userinput):
if userinput == TEXT_TO_MATCH:
print(True)
input_box.delete(0, END)
else:
print(False)
return True
window = Tk()
window.title('Delete after validation')
reg = window.register(validate)
input_box = Entry(window, validatecommand=(reg, '%P'), validate='all')
input_box.pack()
window.mainloop()
The entry widget automatically resets the validate option to "none" when you edit the entry widget from within the validation function.
You can re-enable the validation by using after_idle to reset the validate option after control has been returned to mainloop
def validate(userinput):
if userinput == TEXT_TO_MATCH:
input_box.delete(0, END)
input_box.after_idle(lambda: input_box.configure(validate="all"))
return True

Clearing Placed Labels in Tkinter

So I have a currency which is increasing (that system is working fine). The first part updates the label every 100 ms. I have another button which triggers the second function which is supposed to clear the labels from the first. It sets home_status equal to 0 which should in theory run Money.place_forget() to clear the code. I have tested each part individually and it works but when I put the clears inside the elif statement it doesn't. It does not give me any errors, it just simply doesn't do anything (it does print END OF UPDATE HOME so the elif is triggered).
Any suggestions?
def updatehome(self):
print("UPDATE HOME")
global buy_button, home_status, currency
MoneyLabel = Label(self, text = "Money: ")
MoneyLabel.place(x = 5, y = 70)
Money = Label(self, text=currency)
Money.place(x = 50, y = 70)
if (home_status == 1):
self.after(100, self.updatehome)
elif (home_status == 0):
print("END OF UPDATE HOME")
Money.place_forget()
MoneyLabel.place_forget()
def clearhome(self):
print("CLEAR HOME")
global home_status
home_status = 0
you are creating ten labels every second, all stacked on top of each other, but you are only deleting the very last label you create.

tkinter's IntVar() and .get()'ing it

Im in a need of a little help here, i feel like i have searched endlessly and been unable to corret my problem.
The case:
I have a checkbutton which have on value as 1 and off as 0, now i want to do an act if it is on and another if it is off.
My code goes:
#==Checkbox==#
check = IntVar()
checkbox = Checkbutton(labelframe, text="Tillad mere end én linje", variable = check, onvalue=1, offvalue=0)
checkbox.pack(side = RIGHT)
...
def go():
check.get()
print(check)
if(check == 0):
print("off")
w.delete(ALL)
tegnefladen()
update()
else:
print("on")
update()
You aren't actually setting the value. check is an object, and it won't ever be identical to 0. Basically, you want to compare check.get(). Try this:
def go():
print(check.get())
if(check.get() == 0):
print("off")
w.delete(ALL)
tegnefladen()
update()
else:
print("on")
update()

Categories

Resources