Search code examples
pythonuser-interfacetkinternameerrortkinter-entry

Tkinter problem creating button to collect text from user


I am new to Tkinter, and am trying to create a hangman app. I have already created a command-line version, so I thought it would be a nice beginning project. When learning I was told to use window.mainloop() for creating/updating, but my program contains a while loop, and so that hasn't worked. I am not able to type into the textbox i have created at all and when I click the button, it gives me a NameError saying textEntry in my click() method is not defined. Any help or guidance of where else to look would be much appreciated. Thanks! My code is posted below

from tkinter import *
from random import choice

def click():
        guess = textEntry.get()
        return guess
def main():
        input_file = open('hangman_word_list.txt','r')
        word_list = input_file.read().split()
        window = Tk()
        window.title("Play Hangman!")
        window.configure(background="black")
        p1 = PhotoImage(file='h1.gif')
        p2 = PhotoImage(file='h2.gif')
        p3 = PhotoImage(file='h3.gif')
        p4 = PhotoImage(file='h4.gif')
        p5 = PhotoImage(file='h5.gif')
        p6 = PhotoImage(file='h6.gif')
        Label(window,image=p1,bg="purple").grid(row=0,column=0,columnspan=4)
        word = choice(word_list)
        correctList = list(word)
        lettersLeft = len(word)
        hiddenWord = ('*' * lettersLeft)
        wrongGuessList = []
        lives = 6
        again = True
        nowPhoto = p1
        guess = 'empty'
        while lettersLeft > 0 and again == True:
                Label(window,text="Your word is "+hiddenWord ,bg="gray",fg="purple",font="none 12 bold").grid(row=1,column=0,sticky=W)
                Label(window,text="Enter a letter: " ,bg="gray",fg="purple",font="none 12 bold").grid(row=2,column=0,sticky=W)
                textEntry = Entry(window,width=5,bg="white")
                textEntry.grid(row=2,column=1,sticky=W)
                guess = Button(window,text="Guess",width=5,command=click).grid(row=3,column=2,sticky=W)
                window.update()
main()

Solution

  • The mainloop() listens continously for any hook that you have defined, which means you don't have to worry about that. Just define the right hooks, like the button command.

    I introduced a nicer way to handle the images by putting them in a list and then reducing the list for each image requested. This makes it easier to update the image.

    Then put all processing, like checking if a uessed letter is in the word etc. in the click() function.

    from tkinter import *
    
    window = Tk()
    
    # Make a list of all the pictures
    pic_list = ['h6.gif','h5.gif','h4.gif','h3.gif','h2.gif','h1.gif']
    
    img = PhotoImage(file=pic_list.pop())       # Get image from list of images
    hangman = Label(window, image=img)          # Save reference to the Label as 
    hangman.grid(row=0,column=0,columnspan=4)   #       you will update it later
    
    # I simplified the word selection a bit
    word = 'Wensleydale'
    
    correctList = list(word)
    lettersLeft = len(word)
    hiddenWord = ('*' * lettersLeft)
    wrongGuessList = []
    guess = 'empty'
    
    # Build the rest of the GUI
    Label(window,text="Your word is " + hiddenWord, bg="gray", fg="purple",
          font="none 12 bold").grid(row=1, column=0, sticky=W, columnspan=4)
    Label(window,text="Enter a letter: ", bg="gray", fg="purple",
          font="none 12 bold").grid(row=2, column=0, sticky=W)
    textEntry = Entry(window, width=10, bg="white")
    textEntry.grid(row=2, column=1, sticky=W, columnspan=3)
    
    def click():    # Callback function
        guess = textEntry.get()
    
        # Put all other processing here. 
    
        # Updating the image
        img = PhotoImage(file=pic_list.pop())   # Get next image from list
        hangman.configure(image=img)            # Replace image in label
        hangman.image = img             # Keep reference to the new image
    
    # Create button and associate it with the command callback function
    guess_button = Button(window, text="Guess", width=5,
                          command=click).grid(row=3, column=2, sticky=W)
    
    window.mainloop()   # Will loop continously listening for buttonpress