1
\$\begingroup\$

I've been developing my first real python gui-program for a while now. Having watched some tutorials to tkinter and OOP I've gotten quite far, but now I just can't get my code to do what I want it to.

So here's my code so far:

import random
import string
import time
import datetime
import tkinter as tk
import pandas as pd

# GUI

# Define text variabels:
intro_txt = "Welcome to Typetrainer!\n This program will help you get faster at typing on your PC"

instr_txt = "Instructions:\n-Place your right index finger on the letter J, your left index finger on F" \
         "\n-Type the string you see as fast as you can using all ten fingers" \
         "\n-Don't look at the keyboard !"

diff_txt = "Please select a difficulty"

go_txt = "Type the above string as fast as you can and hit enter !"

# Create custom fontvariables

NORMAL_FONT=("Verdana", 12)
LARGE_FONT=("Verdana", 18)

# Define difficulties

diff_levels = {"Easy": 5, "Medium": 10, "Hard": 15, "Expert": 20}

class TypeTrainerGUI(tk.Tk):
    def __init__(self, *args, **kwargs):  # initialize the TypeTrainerGUI class; 
        # *args: generally used for all the arguments, **kwargs: passing through dictionaries
        tk.Tk.__init__(self, *args, **kwargs)  # initialize Tkinter within the TypeTrainerGUI class
        container = tk.Frame(self)

        container.pack(side="top", fill="both", expand=True)

        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}  # this holds all the different "windows" that the GUI can show and the user can interact with

        for F in (StartPage, DifficultySelection, TypePage):  # "activates" the frames so that 
            # they can be cycled through

            frame = F(container, self)

            self.frames[F] = frame

            frame.grid(row=0, column=0, sticky="nsew")  # .grid defines where the frame sits; sticky defines 
            # alignment and strech

        self.title("Type Trainer")

        self.show_frame(StartPage)

    def show_frame(self, cont):  # define the .show_page method; moves a frame to the top so 
        # the user can interact with it

        frame = self.frames[cont]
        frame.tkraise()

    def init_game(self, diff_in):  # set the parameters for the game to run with

        global cnt
        global score

        print(diff_in) # check if the correct value is passed

        # Define a object that creates a lowercase letter string of length a

        self.question_txt = ''.join(random.choice(string.ascii_lowercase) for x in range(diff_in))

        print(self.question_txt) # check if correct text is generated

        cnt = 0  # Counter for the no of rounds
        score = 0  # Track the score

class StartPage(tk.Frame):  # Create start page

    def __init__(self, parent, controller):  # initialize the frame
        tk.Frame.__init__(self, parent)  # initialize tkinter
        label = tk.Label(self, text=intro_txt, font=LARGE_FONT)  # create label
        label_2 = tk.Label(self, text=instr_txt, font=NORMAL_FONT)  # create label

        label.pack(pady=10, padx=10)
        label_2.pack(pady=10, padx=10)

        next = tk.Button(self, text="Next", command=lambda: controller.show_frame(DifficultySelection))
        next.pack()

class DifficultySelection(tk.Frame):  # Create difficulty selection page

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text=diff_txt, font=NORMAL_FONT, justify=tk.LEFT)
        label.pack(pady=10, padx=10)

        self.choice = tk.IntVar()

        for (diff, val) in diff_levels.items():
            tk.Radiobutton(self, text=diff, padx=20, variable=self.choice, value=val,
                           command=lambda: controller.init_game(self.choice.get())).pack(anchor=tk.W)

        start = tk.Button(self, text="Start game", command=lambda: controller.show_frame(TypePage))
        start.pack()


class TypePage(tk.Frame):  # Create the interaction page

    def __init__(self, parent, init_game):

        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text=go_txt, font=NORMAL_FONT)
        label.pack(pady=10, padx=10)

        question = tk.Label(self, text=question_txt, font=NORMAL_FONT)
        question.pack(pady=10, padx=10)

        usr_input = tk.Entry(self)
        usr_input.pack(pady=10, padx=10)
        usr_input.focus_set()

gui = TypeTrainerGUI()
gui.mainloop()

Ok, so what I want to do is get the value that's selected by clicking a radiobutton and pass it to init_game to create question_txt (and other stuff but I'm leaving that out for now). To do this I use this part of code

self.choice = tk.IntVar()

            for (diff, val) in diff_levels.items():
                tk.Radiobutton(self, text=diff, padx=20, variable=self.choice, value=val,
                               command=lambda: controller.init_game(self.choice.get())).pack(anchor=tk.W)

This all works just fine. init_game does what I want it to do (checked with print(diff_in) and print(question_txt)). Now I want to use question_txt in the TypePage class as text for the question label.

question = tk.Label(self, text=question_txt, font=NORMAL_FONT)
        question.pack(pady=10, padx=10)

Doing this throws a name error: "name 'question_txt' is not defined". I just don't get how I can use question_txt in a different class. I tried to make it a global variable, but that also didn't solve the problem.

I would really appreciate any help with this. Thanks !

N.B.: Since this is my first try at OOP AND tkinter please be leneant. Though all comments on how to write better/more understanbale code are greatly appreciated !

\$\endgroup\$
2
  • 3
    \$\begingroup\$ Welcome to Code Review! Unfortunately "[...] but now I just can't get my code to do what I want it to." makes your question off-topic, since we only review code that is fully working to the best of your knowledge here on this site. Stack Overflow is usually the place to go to if you're looking for help to get a program working the way you want. Once it works, we will be more than happy to provide feedback about possible improvements. \$\endgroup\$ – AlexV Sep 10 '19 at 12:35
  • 3
    \$\begingroup\$ Alright, I'll move it there then. Thanks ! \$\endgroup\$ – L.Thoma Sep 10 '19 at 12:37