CONTEXT I programmed a hangman game on python and used "tkinter" for its GUI. It works perfectly. I switched from tkinter to "customtkinter" and "CTkMessagebox" to have a GUI with a better visual, eveyrthin works perfectly except one thing.
PROBLEM When my program check the entry of the user (to make sure it's a letter without an accent or a cedilla), a message box with an error message pops up if the entry is incorrect. But with CTkMessagebox nothin I receive the following error:
Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\thiba\AppData\Local\Programs\Python\Python312\Lib\tkinter_init_.py", line 1948, in call return self.func(*args) ^^^^^^^^^^^^^^^^ File "C:\Users\thiba\AppData\Local\Programs\Python\Python312\Lib\site-packages\customtkinter\windows\widgets\ctk_button.py", line 554, in _clicked self._command() File "c:\Users\thiba\OneDrive\Documents\Studies\Programming\Python\Hangman\Hangman (with customtkinter)", line 32, in game CTkMessagebox(master=root, title="Entry error", message="Only letters (without an accent or a cedilla) can be entered.", icon="warning") File "C:\Users\thiba\AppData\Local\Programs\Python\Python312\Lib\site-packages\CTkMessagebox\ctkmessagebox.py", line 57, in init super().init() File "C:\Users\thiba\AppData\Local\Programs\Python\Python312\Lib\site-packages\customtkinter\windows\ctk_toplevel.py", line 36, in init super().init(*args, **pop_from_dict_by_set(kwargs, self.valid_tk_toplevel_arguments)) File "C:\Users\thiba\AppData\Local\Programs\Python\Python312\Lib\tkinter_init.py", line 2681, in init self.title(root.title()) ^^^^^^^^^^^^ TypeError: 'str' object is not callable
WHAT I TRIED
Here is my code
from Dictionary import dico
from Drawings import drawings
import random
import customtkinter as CTk
from CTkMessagebox import CTkMessagebox
word_guess = dico[random.randrange(len(dico) - 1)]
word_hidden = " _" * len(word_guess)
drawing_nb = 0
tries = 0
list = []
print(word_guess)
#------------------------------- GAME LOOP -------------------------------#
def game(*args):
global word_guess
global word_hidden
global tries
global drawings
global drawing_nb
letter_tried = f2_var_LetterTried.get().lower()
letters_tried = f2_var_LettersTried.get()
# Check the entry
if not (letter_tried.isalpha() and letter_tried.isascii()):
CTkMessagebox(master=root, title="Entry error", message="Only letters (without an accent or a cedilla) can be entered.", icon="warning")
return
# Check if the word/letter has already been tried
for string in list:
if letter_tried == string:
f2_ent_WordEntry.delete(0, CTk.END)
return
tries +=1
# For a letter
if len(letter_tried) == 1:
# Check if the letter has already been tried
for string in list:
if letter_tried == string:
f2_ent_WordEntry.delete(0, CTk.END)
return
if letter_tried not in (word_guess or word_hidden):
drawing_nb += 1
f2_var_drawing.set(drawings[drawing_nb])
if letters_tried == "":
letters_tried += letter_tried
f2_var_LettersTried.set(letters_tried)
else:
letters_tried += ", " + letter_tried
f2_var_LettersTried.set(letters_tried)
else:
letter_pos = 1
for char in word_guess:
if letter_tried == char:
word_hidden = word_hidden[:letter_pos * 2 - 1] + letter_tried + word_hidden[letter_pos * 2:]
letter_pos += 1
f2_var_WordHidden.set(word_hidden)
# For a word
# Check if the word has already been tried
for string in list:
if letter_tried == string:
f2_ent_WordEntry.delete(0, CTk.END)
return
if len(letter_tried) >1:
if letter_tried == word_guess:
end_game(f'Congratulations, you have found the word "{word_guess}"" in {tries} tries!')
return
else:
drawing_nb += 1
f2_var_drawing.set(drawings[drawing_nb])
if letters_tried == "":
letters_tried += letter_tried
f2_var_LettersTried.set(letters_tried)
else:
letters_tried += ", " + letter_tried
f2_var_LettersTried.set(letters_tried)
if "_" not in word_hidden:
end_game(f"Congratulations, you have found the word {word_guess} in {tries} tries!")
return
if drawing_nb == 10:
end_game(f'Game Over, the word was "{word_guess}".')
list.append(letter_tried)
f2_ent_WordEntry.delete(0, CTk.END)
#------------------------------- CHANGING FRAME -------------------------------#
def first_game():
root.bind("<Return>", game)
f2_ent_WordEntry.focus()
frame2.tkraise()
def end_game(message):
global drawings
global drawing_nb
f3_lb_EndMessage.configure(text=message)
f3_lb_drawing.configure(text=drawings[drawing_nb])
root.bind("<Return>","")
frame3.tkraise()
def new_game():
global word_guess
global word_hidden
global tries
global drawings
global drawing_nb
global f2_var_LettersTried
global list
word_guess = dico[random.randrange(len(dico) - 1)]
word_hidden = " _" * len(word_guess)
drawing_nb = 0
tries = 0
list = []
f2_var_LettersTried.set("")
f2_var_WordHidden.set(word_hidden)
f2_var_drawing.set(drawings[drawing_nb])
f2_ent_WordEntry.delete(0, CTk.END)
f2_ent_WordEntry.focus()
root.bind("<Return>", game)
frame2.tkraise()
print(word_guess)
#------------------------------- START WINDOW -------------------------------#
# Create main application window
root = CTk.CTk()
root.title = "The Hangman"
root.geometry("750x300")
# Create 1ST frame2
frame1 = CTk.CTkFrame(root)
frame1.grid(column=0, row=0, sticky="news")
# Label for drawings
f1_lb_hangman = CTk.CTkLabel(frame1, text=drawings[10], font=("Consolas", 12), justify="left")
f1_lb_hangman.grid(column=0, row=0, rowspan=4)
# Label for title
f1_lb_title = CTk.CTkLabel(frame1, text="THE HANGMAN", font=("Consolas", 20))
f1_lb_title.grid(column=1, row=0, columnspan=2)
# Label for signature
f1_lb_signature = CTk.CTkLabel(frame1, text="By T.D.", font=('Consolas', 9))
f1_lb_signature.grid(column=1, row=1, columnspan=2, sticky="n")
# Button for starting a game
f1_btn_start = CTk.CTkButton(frame1, text="Start a game", command=first_game)
f1_btn_start.grid(column=1, row=2, columnspan=2)
#------------------------------- IN-GAME WINDOW -------------------------------#
# Create 2ND frame
frame2 = CTk.CTkFrame(root)
frame2.grid(column=0, row=0, sticky="news")
# Label for drawings
f2_var_drawing = CTk.StringVar()
f2_var_drawing.set(drawings[drawing_nb])
f2_lb_drawing = CTk.CTkLabel(frame2, textvariable=f2_var_drawing, font=("Consolas", 12), justify="left")
f2_lb_drawing.grid(column=0, row=0, rowspan=4)
# Label for title
f2_lb_title = CTk.CTkLabel(frame2, text="THE HANGMAN", font=("Consolas", 20))
f2_lb_title.grid(column=1, row=0, columnspan=2)
# Label for signature
f2_lb_signature = CTk.CTkLabel(frame2, text="By Thibaud D.", font=('Consolas', 9))
f2_lb_signature.grid(column=1, row=1, columnspan=2, sticky="n")
# Label for hidden word
f2_var_WordHidden = CTk.StringVar()
f2_var_WordHidden.set(word_hidden)
f2_lb_WordHidden = CTk.CTkLabel(frame2, textvariable=f2_var_WordHidden, font=("Consolas", 12), wraplength=500)
f2_lb_WordHidden.grid(column=1, row=2, columnspan=500)
# Labels for letters tried
f2_var_LettersTried = CTk.StringVar()
f2_lb_LettersTried = CTk.CTkLabel(frame2, textvariable=f2_var_LettersTried, font=("Consolas", 12), justify="left")
f2_lb_LettersTried.grid(column=2, row=3)
CTk.CTkLabel(frame2, text="Previous tries:", font=("Consolas", 12), justify="right").grid(column=1, row=3, sticky="e")
# Entry to try letter/word
f2_var_LetterTried = CTk.StringVar()
f2_ent_WordEntry = CTk.CTkEntry(frame2, textvariable=f2_var_LetterTried)
f2_ent_WordEntry.grid(column=1, row=4, sticky="w")
# Button to try entry
f2_btn_try = CTk.CTkButton(frame2, text="Try", command=game)
f2_btn_try.grid(column=2, row=4, sticky="w")
#------------------------------- END-GAME WINDOW -------------------------------#
# Create 3RD frame
frame3 = CTk.CTkFrame(root)
frame3.grid(column=0, row=0, sticky="news")
# Label for drawings
f3_lb_drawing = CTk.CTkLabel(frame3, font=("Consolas", 12), justify="left")
f3_lb_drawing.grid(column=0, row=0, rowspan=4)
# Label for title
f3_lb_title = CTk.CTkLabel(frame3, text="THE HANGMAN", font=("Consolas", 20))
f3_lb_title.grid(column=1, row=0, columnspan=2)
# Label for signature
f3_lb_signature = CTk.CTkLabel(frame3, text="By Thibaud D.", font=('Consolas', 9))
f3_lb_signature.grid(column=1, row=1, columnspan=2, sticky="n")
# Label for end message
f3_lb_EndMessage = CTk.CTkLabel(frame3, font=("Consolas", 12), wraplength=500, justify="left")
f3_lb_EndMessage.grid(column=1, row=2, columnspan=500)
# Labels for letters tried
f3_lb_LettersTried = CTk.CTkLabel(frame3, textvariable=f2_var_LettersTried, font=("Consolas", 12), justify="left", )
f3_lb_LettersTried.grid(column=2, row=3)
CTk.CTkLabel(frame3, text="Previous tries:", font=("Consolas", 12), justify="right").grid(column=1, row=3, sticky="e")
# Button to try entry
button_try = CTk.CTkButton(frame3, text="Start a new game", command=new_game)
button_try.grid(column=2, row=4, sticky="w")
frame1.tkraise()
root.mainloop()
You have override the title()
function by the following line:
root.title = "The Hangman"
So when tkinter calls root.title()
internally, it raises exception.
Change the problem line to:
root.title("The Hangman")