Tkinter -- Why won't my button execute a command? - python

I'm sure I'm missing something laughably obvious, but I've been staring at this for 20 minutes and I have no idea what it is.
class GUI:
def __init__(self):
# creating frame and window
self.winMain = tk.Tk()
self.topFrame = tk.Frame(self.winMain)
self.midFrame = tk.Frame(self.winMain)
self.botFrame = tk.Frame(self.winMain)
# creating labels
self.wordLabel = tk.Label(self.topFrame,text="Word to unscramble",width=18)
self.wordLabel.pack(side="left")
# scrambled word
self.scrambledWord = tk.StringVar()
# open file of scrambled words
dictList = open('dict.txt', 'r')
words = [] # empty list to fill with words
for line in dictList:
words.append(line)
word = random.choice(words)
print(word)
word = ''.join(random.sample(word, len(word)))
self.scrambledWord.set(word)
# label of scrambled word
self.ScWd = tk.Label(self.topFrame, textvariable=self.scrambledWord, width=len(word))
self.ScWd.pack(side="right")
# entry label
self.guessIn = tk.Label(self.midFrame,text="Your guess:", width=15)
self.guessIn.pack(side="left")
# input box
self.guess = tk.Entry(self.midFrame, width=15)
self.guess.pack(side="right")
# guess button
self.guessButton = tk.Button(self.botFrame,text="Guess",command=self.guess)
self.guessButton.pack(side="left")
# status variable
self.stat = tk.StringVar()
# status label
self.status = tk.Label(self.botFrame, textvariable=self.stat,width=10)
self.status.pack(side="right")
self.topFrame.pack(side="top")
self.midFrame.pack()
self.botFrame.pack()
tk.mainloop()
def guess(self):
correct = False
userGuess = self.guess.get()
self.stat.set(userGuess)
if userGuess == self.scrambledWord:
self.stat.set("correct")
correct = True
print(correct)
Sorry for posting the entire thing, but I have no idea where the problem lies. any help is much appreciated.

Related

Python tkinter - Change the Label created by a loop, how can I do?

I read a lot for it and I have the sentiment that there is no solution for me.
Context: user has to enter 6-digit calculation number in the entries. The 9x entries are created by a loop. I wrote the condition to detect if the user did a mistake : number which contains less or more than 6 digit or / and contains a letter. They are working, I tested them. Only 6-digit number are accepted (if 0, it's ok since it means that the user just need to get less than 9x documents).
Goal: if the user did one mistake, a message "Error in the number" at the place of the "0" has to appear right next to the concerned and "faulty" entry.
Everything will be activated through a button.
What I tried: with a list, but it doesn't work.
How can I change the Label dynamically created by the loop ?
user_entries=[]
error_list_length=[0,0,0,0,0,0,0,0,0]
error_list_letters=[0,0,0,0,0,0,0,0,0]
error_calculation_list=[0,0,0,0,0,0,0,0,0]
nbofcalc=9
a=0
b=1
ddd=791250
#------ Function to check if the entered calculation number are composed of 6 characters (mandatory)
def check_calc_number():
global gg_error
gg=0
gg_error=0
while gg<nbofcalc:
if len(user_entries[gg].get()) != 6:
if len(user_entries[gg].get()) ==0:
gg_error+=0
error_list_length[gg]=0
else:
gg_error+=1
error_list_length[gg]=1
else:
gg_error+=0
error_list_length[gg]=0
gg+=1
#------ Function to check if the entered calculation number contains a or many letters (prohibited)
def check_calc_letter():
global hh_error
hh=0
hh_error=0
alphabet_x='a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
for x in range(nbofcalc):
for n in user_entries[hh].get():
if n in alphabet_x:
hh_error+=1
error_list_letters[hh]=1
hh+=1
#------ Function to check with entries has an error and update the list "error_calculation_list" to try to displays the message "Error in the number" next to the concerned entries
def error_length_letters_display():
ww=0
while ww<nbofcalc:
if error_list_length[ww]==1 :
error_calculation_list[ww]="Error"
var_calculation.set(error_calculation_list[ww])
if error_list_letters[ww]==1:
error_calculation_list[ww]="Error"
var_calculation.set(error_calculation_list[ww])
ww+=1
#----- Loop to crate the entries and Label
for x in range(nbofcalc):
cadre1=Frame(fenetre)
cadre1.pack(side=TOP,anchor=NW)
cadre=Frame(cadre1)
cadre.pack()
c=str(b)
calc=Label(cadre,text="Calculation "+c+" ")
calc.pack(side=LEFT)
var_entry=StringVar()
my_entry=Entry(cadre,textvariable=var_entry, bd=5)
my_entry.insert(0,ddd)
my_entry.pack(side=LEFT)
var_calculation=StringVar()
var_calculation.set(error_calculation_list[a])
calc_error_frame=Label(cadre, textvariable=var_calculation) # The Label to change if error
calc_error_frame.pack(side=RIGHT)
user_entries.append(my_entry)
a+=1
b+=1
ddd+=1
Thank you !
You can store values and objects you need to change, so then you can change them dinamically. See this example
from tkinter import *
r = Tk()
my_entries = []
for i in range(5):
e = Label(r, text=i)
my_entries.append(e)
e.pack(side='top')
r.after(4000, lambda: my_entries[2].configure(text='Example'))
r.mainloop()
EDIT 1:As TheLizzard and Cool Cloud pointed out, it's better to avoid using time.sleep() while using tkinter. Replaced with non-blocking after()
you could setup the trace function for tk.StringVar(), when user enter any value into Entry, it will be checked. for example as shown on below user only can type decimal, and you and setup length as well.
def create_widgets(self):
self.vars = tk.StringVar()
self.vars.trace('w', partial(self.validate2, 1, 1))
# Min Voltage Validating Part
self.vars1 = tk.StringVar()
self.vars1.trace('w', partial(self.validate2, 2, 2))
# Max Voltage Validating Part
self.vars2 = tk.StringVar()
self.vars2.trace('w', partial(self.validate2, 3, 4))
# Current Validating Part
self.vars3 = tk.StringVar()
self.vars3.trace('w', partial(self.validate2, 4, 3))
# Channel Validating Part
# function( key, size)
self.enter_info = tk.Label(self, text="Please enter your information: ", bg="lightgrey")
self.enter_info.grid(tke_Table_EnterInfo)
self.voltage = tk.Label(self)
self.voltage["text"] = "MinVoltage"
self.voltage.grid(tke_Label_MinVoltage)
self.voltageInput = tk.Entry(self, width=10, textvariable=self.vars).grid(tke_StringBox_MinVoltage)
self.vars.set(0)
# Min Voltage Validating Part
self.current = tk.Label(self)
self.current["text"] = "MaxVoltage"
self.current.grid(tke_Label_MaxVoltage)
self.currentInput = tk.Entry(self, width=10, textvariable=self.vars1).grid(tke_StringBox_MaxVoltage)
self.vars1.set(5)
# Max Voltage Validating Part
self.power = tk.Label(self)
self.power["text"] = "Current"
self.power.grid(tke_Label_MaxCurrent)
self.powerInput = tk.Entry(self, width=10, textvariable=self.vars2).grid(tke_StringBox_MaxCurrent)
self.vars2.set(62.5)
# Max Current Validating Part
self.channel = tk.Label(self)
self.channel["text"] = "channel"
self.channel.grid(tke_Label_Channel)
self.channelInput = tk.Entry(self, width=10, textvariable=self.vars3).grid(tke_StringBox_Channel)
self.vars3.set(8)
# Max Channel Validating Part
def validate2(self, key, size, *args):
# TODO:add more information
if key == 1:
value = self.vars.get()
elif key == 2:
value = self.vars1.get()
elif key == 3:
value = self.vars2.get()
else:
value = self.vars3.get()
if not value.isdecimal():
print(len(value))
# if len(value) < 2:
corrected = ''.join(filter(str.isdecimal, value))
if key == 1:
self.vars.set(corrected)
elif key == 2:
self.vars1.set(corrected)
elif key == 3:
self.vars2.set(corrected)
else:
self.vars3.set(corrected)
if key == 1:
corrected = self.vars.get()
corrected = corrected[0:size]
self.vars.set(corrected)
elif key == 2:
corrected = self.vars1.get()
corrected = corrected[0:size]
self.vars1.set(corrected)
elif key == 3:
corrected = self.vars2.get()
corrected = corrected[0:size]
self.vars2.set(corrected)
else:
corrected = self.vars3.get()
corrected = corrected[0:size]
self.vars3.set(corrected)

Connect a python script with Tkinter

I want to design a Gui script for a NameSort script.
I want to develop a python3 script with Gui. Here is my code for Cli only
text = open('/Users/test/Desktop/readme.txt','r')
def readtxt(txt): #turns txt to ls
dictls=(txt.read()).splitlines()
return dictls
def getdict(dictls): #turns to dictionary
dict1 = {dictls.index(i) : i for i in dictls}
return dict1
def getkey(diction,index): #getkey
return diction[index]
def randomord(x,z): #random order generator, won't generate repeditive numbers
import random
output = []
done = []
y = 0 #already generated
while y <= x:
rnum = random.randint(0,z)
if rnum not in done:
output.append(rnum)
done.append(rnum)
y+=1
return output
def main():
ls=readtxt(text)
while True:
print(f'\nThere are {len(ls)} names on the list.')
try:
h = int(input('Number of names to gen: '))
if h-1 <= len(ls)-1:
outls = [getkey(getdict(ls),i) for i in randomord(h-1,len(ls)-1)]
print('\n'.join(outls))
else:
print(f'[*]ERR: There are only {len(ls)} names on the list.')
except:
print('[*]ERR')
main()
Now I have tried these code
text = open('/root/Desktop/Python/gui/hell.txt','r')
def readtxt(txt): #turns txt to ls
dictls=(txt.read()).splitlines()
return dictls
def getdict(dictls): #turns to dictionary
dict1 = {dictls.index(i) : i for i in dictls}
return dict1
def getkey(diction,index): #getkey
return diction[index]
def randomord(x,z): #random order generator, won't generate repeditive numbers
import random
output = []
done = []
y = 0 #already generated
while y <= x:
rnum = random.randint(0,z)
if rnum not in done:
output.append(rnum)
done.append(rnum)
y+=1
return output
def main():
ls=readtxt(text)
while True:
print(f'\nThere are {len(ls)} names on the list.')
try:
h = int(input('Number of names to gen: '))
if h-1 <= len(ls)-1:
outls = [getkey(getdict(ls),i) for i in randomord(h-1,len(ls)-1)]
print('\n'.join(outls))
else:
print(f'[*]ERR: There are only {len(ls)} names on the list.')
except:
print('[*]ERR')
global startmain
startmain = 0
def test1():
startmain = 1
###########################
##########################
###################################
from tkinter import *
import tkinter as tk
window = tk.Tk()
p1 = tk.Label(
text="Thomas-name-sort",
fg="red",
bg='green',
width=10,
height=8
)
name_ent = tk.Label(text="输入生成数量Number of names to gen:")
entry = tk.Entry()
name_ent.pack()
entry.pack()
name = entry.get()
b1 = tk.Button(
text="auto-testing自检",
bg="blue",
fg="orange",
width=20,
height=5,
command=test1()
)
b1.pack()
if startmain == 1:
main()
#bind-zone
window.mainloop()
It does not work.
I want to design a Gui script for a NameSort script.
I could not bind the button with the function
T have tried "command=main()" and "button.bind("", func=main()"
Please help me!!!
To set a button's function in tkinter, you only pass the function itself in the command parameter i.e.
command = test1,
Not command = test1() as in this case you are just giving it the result of the function (which is None). This is so that it can execute the function each time the button is pressed.
If you want to provide in arguments for it to execute, you'll then have to use a lambda function:
command = lambda: test1(param1, param2),
You can find decent guides on buttons in tkinter here if you're interested

How do I get a tkinter screen that isn't the root to disapere using either the destroy or withdraw fuction?

I have a log and quiz system using tkinter GUI. The gui screen allows for loging in and registering. This infomation is stored on an excel file saved as a csv.
The quiz portion is done on the python shell. What I want to do, is hide both the log in screen and main screen once the user has logged in and then if they choose the option of Logout, by entering 'D'. The main screen then comes back up.
I have been successful in getting rid of the main screen using the .withdraw function and can get it to appear back using, .deconify. But for some reason, I can't get rid of the log in screen.
It is possible that it's just in the wrong place, but I get an Attribute Error, which states 'function' object has no attribute 'withdraw'(I get the same for destroy)
Below is my code. It's not all of it. But the parts I think you'd need to be able to fix it.
def Destroy_menu():
main_screen.withdraw()
Login.withdraw()
def Quiz(quizfile, User):
print(User, quizfile)
global var
NumberList = [1,2,3,4,5,6,7]
Questions = True
score = 0
questions_answered = 0
while Questions == True:
try:
Number = random.choice(NumberList)
NumberList.remove(Number)
File = open(quizfile + ".csv", "r")
for line in File:
details = line.split(",")
ID_Number = int(details[0])
if ID_Number == Number:
Question = (details[1])
print("Question:",Question)
Answer_one = (details[2])
print("A):",Answer_one)
Answer_Two = (details[3])
print("B):",Answer_Two)
Answer_Three = (details[4])
print("C):",Answer_Three)
Correct = (details[8])
var = StringVar()
X = input("Answer (e.g. A): ")
print("\n")
if X == Correct:
print("Correct")
score += 1
print("Score:", score)
questions_answered = questions_answered + 1
else:
print("Incorrect, answer was:",Correct)
print("Score:", score)
print("\n")
questions_answered = questions_answered + 1
except:
File.close()
print("Quiz Completed")
print("Final Score:", score, "/ 7")
input("Press enter to continue")
Questions = False
#Writing to file
file_writer = csv.writer(open(r"E:\NEA\Quiz\Scores.csv","a",newline =""))
file_writer.writerow([User,quizfile,score,"NA"])
Quiz_choice(User)
def Quiz_choice(User):
Destroy_menu()
flag = False
print("\n" * 50)
print("Pick a quiz")
print("English Quiz (A)")
print("Maths Quiz (B)")
print("Science Quiz (C)")
print("Logout(D)")
while flag == False:
opt = input(">>>: ")
opt = opt.upper()
if opt == "A":
quizfile = "English"
Quiz(quizfile,User)
flag = True
elif opt == "B":
quizfile = "Maths"
Quiz(quizfile,User)
flag = True
elif opt == "C":
quizfile = "Science"
Quiz(quizfile,User)
flag = True
elif opt == "D":
print("Goodbye")
main_screen()
main_screen = Tk()
main_screen.deiconify()
else:
print("Invalid input. Please input a letter")
def Login():
global login_screen
Login_screen = Toplevel(main_screen)
Login_screen.title("Log in")
Login_screen.geometry ("400x234")
Label(Login_screen, text = "Please enter details below to login").pack()
Label(Login_screen, text = "").pack()
global Username_verify
global Password_verify
Username_verify = StringVar()
Password_verify = StringVar()
global Username_login_entry
global Password_login_entry
Label(Login_screen, text = "Username").pack()
Username_login_entry = Entry(Login_screen, textvariable = Username_verify)
Username_login_entry.pack()
Label(Login_screen, text = "").pack()
Label(Login_screen , text = "Password").pack()
Password_login_entry = Entry(Login_screen, textvariable = Password_verify, show = '*')
Password_login_entry.pack()
Label(Login_screen, text ="").pack()
Button(Login_screen, text = "Log in", width = 10, height = 20,command = Login_verify).pack()
Thanks in advance, and ask any questions you need to.

Base 10 Error with passing an int

The error i keep getting is when i try to determine weather the player has enough guesses left to keep playing. i am unable to figure it out does anyone have any idea how to fix this issue please i am stuck.
Also i am a beginner in python and i know there are other easier ways to do this i just do not know how.
here i my error i recieve:
File c: line 68, in initalize_loop
total_guesses = int(total_guesses_left.get())
ValueError: invalid literal for int() with base 10: '[]'
here is my full code below:
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
import random
import os
import sys
#Section the Functions are stored.
def loadWordList(words):
try:
fin = open(words)
for line in fin:
tmp = fin.readline()
wordList.append(tmp.rstrip("\n"))
fin.close
except OSError as err:
print("File Error: ", err, "\n")
exit(1)
def exity():
sys.exit()
def getHint(word, guessed_letter):
#Stores the word in characters in which the player cannot see but still gives the ammount of charaters.
hint = ""
c = 0
while ( c <= (len(word) - 1)):
if word[c] in guessed_letter:
#increments each hint that is correctly guessed unlocking the guessed letter.
hint += word[c]
c += 1
else:
hint += "_"
c +=1
return hint
def countOccurences(word, guess):
c = 0
count = 0
while c <= (len(word)-1):
#Shows the ammount of times the letter occured in that word.
if guess == word[c]:
count +=1
c += 1
else:
c += 1
return count
def get_letter(*args):
guess = inputted_value.get()
guess = guess.lower()
return guess
def valid_guess(guess):
if guess.isalpha() and 1 == len(guess):
return True
else:
user_help.set(invalid_guess)
return False
def final_guess(*args):
finalguess = inputted_value.get()
finalguess = finalguess.lower()
def initalize_loop(*args):
total_guesses = int(total_guesses_left.get())
if ((int(total_guesses > 0)) and (secret_word.get() != word)):
guess = get_letter()
valid = valid_guess(guess)
if valid == True:
if guess in guessed_letter:
invalid_input.set("You have already guessed that letter '{}'".format(guess))
elif guess in word:
invalid_input.set("That is a good guess! '{}' occurs {} time(s) in the secret word.".format(guess, countOccurences(guess, word)))
else:
invalid_input.set("'{}' does not occur in the secret word.".format(guess))
guessed_letter.append(guess)
total_guesses =-1
word_entry.delete(0, 'end')
secret_word_value.set(getHint(word, guesses))
total_guesses_left.set(total_guesses)
print(guessed_letter)
else:
if(secret_word_value.get() == word):
messagebox.showinfo(title= "Winner!", message=("Congradulations! You Correctly guessed the secret word: {}".format(word)))
root.destroy()
else:
finalguess = final_guess()
if finalguess == word:
messagebox.showinfo(frame, title="Congratulations", message= ("Congradulations! You Correctly guessed the secret word: {}".format(word)))
root.destroy()
else:
messagebox.showinfo(title= "Incorrect", message=("Sorry, the secret word was: {} ".format(word)))
root.destroy()
root = Tk()
root.title('COSC 110 Guessing Game' )
frame = ttk.Frame(root, padding = '4 4 15 15')
frame.grid(column=0, row=0, sticky=(N, W, E, S))
inputted_value = StringVar()
user_help = StringVar()
total_guesses_left = StringVar()
secret_word_value = StringVar()
invalid_input = StringVar()
empty = " "
invalid_guess = "Invalid Guess. Please Enter a letter from A-Z"
word_entry= ttk.Entry(frame, width=7)
word_entry.grid(column=2, row=2, sticky=(W, E))
exit_button= ttk.Button(frame, text='Exit', command=exity)
exit_button.grid(column=1, row =7, sticky=(W))
entered_guess = ttk.Label(frame, text='Enter a Letter')
entered_guess.grid(column=1, row=2, sticky=(W, E))
secret_guess = ttk.Label(frame, textvariable=secret_word_value)
secret_guess.grid(column=2, row=1, sticky=(W, E, N, S))
guesses_label= ttk.Label(frame, text='Guesses Remaining:')
guesses_label.grid(column=1, row=3, sticky=(W, E))
total_guesses = ttk.Label(frame, relief ="sunken", textvariable= total_guesses_left)
total_guesses.grid(column=2, row=3, sticky=(W, E))
user_details = ttk.Label(frame, textvariable = user_help)
user_details.grid(column=1, row = 5, sticky=(W, E))
invalid_guesses = ttk.Label(frame, textvariable = invalid_input)
invalid_guesses.grid(column=1, row = 6, sticky =(W, E))
secret_word = ttk.Label(frame, text='Secret Word:')
secret_word.grid(column=1, row=1, sticky=(W, E))
enter_button = ttk.Button(frame, text='Enter', command = initalize_loop)
enter_button.grid(column=3, row =2, sticky=(W, E))
for child in frame.winfo_children():
child.grid_configure(padx=5, pady=5)
enter_button.focus()
enter_button.bind('<Return>', initalize_loop)
if __name__ == "__main__":
if_true = True
while if_true == True:
wordList =[]
loadWordList("Words.txt")
word = random.choice(wordList)
guessed_letter = []
total_guesses = 10
secret_word_value.set(getHint(word, guessed_letter))
total_guesses_left.set(guessed_letter)
invalid_input.set(empty)
user_help.set(empty)
root.mainloop()
if_true = messagebox.askyesno(icon="question", title= "Play Again?", message ="Would you like to play again?")
exit(0)
First you initialize the variable here:
total_guesses_left = StringVar()
Then, inside if __name__ == "__main__": you write:
guessed_letter = []
// ...
total_guesses_left.set(guessed_letter)
So our StringVar instance stored as total_guesses_left gets its value set to an empty list. As it's a StringVar, this leads to a conversion, which means that its internal value now is the string "[]".
Then in your initalize_loop, you try to do
total_guesses = int(total_guesses_left.get())
Of course total_guesses_left.get() will return a string, or more precisely it will return the string "[]".
And as int parses strings representing numbers with a specific base (by default 10), it can only handle strings consisting of alphanumeric characters, and only if they only contain characters used by the specified number base (i.e. by default those are only the characters 0123456789).
Therefore you get the exception that "[]" can not be parsed as int.
You probably want total_guesses_left to store a valid integer representation string and not one of a list.
It means at that moment your total_guesses_left.get() is giving '[]'. base 10 error arises when you try to convert a char or something other than a number which is as a string like
>>> str1='a'
>>> int(str1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'a'
>>> alist='[]'
>>> int(alist)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '[]'
I hope you understand the error. Play around a little with errors. "Trial And Error " :D

For Loop inside Function using a List: not iterating

Hello :) In the typing practice program I am creating in python 3, I have a for...loop that takes the characters from a global list of a certain paragraphs characters and compares it to the character the user is typing.
For some reason, the for loop wont iterate and won't go on to the next character. After some research, I figured out that you have to use local variables in order to do this but that doesn't work either. Here is my code:
import random
from tkinter import *
root=Tk()
a_var = StringVar()
words = []
eachword = []
global eachchar
charlist = []
x=random.randint(0,10)
def typingpractice():
realcharlist = []
something = []
paralist = []
#x=random.randint(0,10)
file = open("groupproject.txt")
line = file.readline()
paraWords = []
for line in file:
newline = line.replace("\n","")
paralist.append(line.replace("\n", ""))
paraWords.append(newline.split(" "))
wordList = []
for c in paraWords[x]:
charlist.append(c)
for b in range(0,len(charlist)):
wordList.append(charlist[b])
#print (wordList)
for p in charlist[b]:
realcharlist.append(p)
#print(realcharlist)
a=Canvas(root, width=500, height=500)
a.pack()
a.create_text(250,50, text = "Typing Fun", width = 500, font = "Verdana", fill = "purple")
a.create_text(250,300, text = paralist[x], width = 500, font = "Times", fill = "purple")
a = Entry(root, width = 100)
a.pack()
a.focus_set()
a["textvariable"] = a_var
def compare(s, realcharlist):
for g in realcharlist:
print ("s:",s)
print ("g:",g)
if s == g:
print ("y")
a['fg'] = 'green'
break
else:
print ("n")
a['fg'] = 'red'
break
def callback(*args):
global s
# print ("b:",xcount)
s = a.get()
s = s[-1:]
compare(s, realcharlist)
a_var.trace_variable("w", callback) #CALL WHEN VARIABLE IS WRITTEN
def practicetest():
print ("nothing here yet")
b = Button(root, text="Start Practice", command=typingpractice)
b.pack()
d = Button(root, text="Test", command=practicetest)
d.pack()
root.mainloop()
The text file "groupproject.txt" is an external text file that contains 10 one-line paragraphs, each character of each paragraph is being compared to what the user is typing in.
Any help on how to make the for loop work would be greatly appreciated. Thanks :D
Basically what happened was there was a break in the for loop so it would always iterate itself starting from 0 again.

Categories