Running another class in the same window using tkinter

Question:

I’m trying to build my first app using python and tkinter.
I’m stuck where I can’t run the content from another class into the same first window.

The first window is a login window, here is the full code of the class:

import tkinter as tk
import sqlite3

from tkinter import *
from gamecontent import Gamecontent

class MainApp(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.title('Word Warrior - Sign In')
        self.geometry("650x510")
        self.resizable(width=False, height=False)
            
        # Create widgets
        self.label_username = tk.Label(self, text="Username")
        self.label_password = tk.Label(self, text="Password")
        self.entry_username = tk.Entry(self)
        self.entry_password = tk.Entry(self, show="*")
        self.button_login = tk.Button(self, text="Login", command=self.login)
        self.button_createacc = tk.Button(self, text="Create Account", command=self.createacc)

        # Place widgets
        self.label_username.place(x=200, y=150)
        self.label_password.place(x=200, y=200)
        self.entry_username.place(x=280, y=152, width=140, height=27)
        self.entry_password.place(x=280, y=202, width=140, height=27)
        self.button_login.place(x=280, y=242, width=140, height=27)
        self.button_createacc.place(x=280, y=282, width=140, height=27)
                
        # Create database and tables and cursor object
        self.conn = sqlite3.connect('users.db')
        self.c = self.conn.cursor()
        self.c.execute("CREATE TABLE IF NOT EXISTS users (username text UNIQUE, password text)")
        self.conn.commit()
        self.conn.close()
   
    def clear_content(self):
        for widget in self.winfo_children():
            widget.destroy()
            
    def login(self):

        # Get the username and password from the entry widgets
        username = self.entry_username.get()
        password = self.entry_password.get()
        
        # Fetch username and password from the database
        conn = sqlite3.connect('users.db')
        c = conn.cursor()
        c.execute("SELECT * FROM users WHERE username=? AND password=?", (username, password))
        result = c.fetchone()
        conn.close()

        # Check if the username and password are correct
        if result:
            # If the login is successful, open a new window with the flashcard game
            self.clear_content()
            Gamecontent()
        else:
            # If the login is not successful, display an error message
            self.label_message = tk.Label(self, text="     Wrong credentials     ")
            self.label_message.place(x=285, y=322)
    
    def createacc(self):

        # Get the username and password from the entry widgets
        username = self.entry_username.get()
        password = self.entry_password.get()

        # Checks if user is entering an empty username/password while creating 
        if username == "" or password == "":
            
            self.label_message = tk.Label(self, text="     Can't be empty     ")
            self.label_message.place(x=290, y=322)

        else:
            # Connect to the database (or create it if it doesn't exist)
            conn = sqlite3.connect('users.db')
            c = conn.cursor()

            # Create the table if it doesn't exist
            c.execute('''CREATE TABLE IF NOT EXISTS users
                        (username text, password text)''')

            # Checks if an account with the same username exists
            c.execute("SELECT * FROM users WHERE username = ?", (username,))
            if c.fetchone() is None:
                c.execute("INSERT INTO users VALUES (?, ?)", (username, password))
                conn.commit()
                self.label_message = tk.Label(self, text="     Account created     ")
                self.label_message.place(x=290, y=322)
            else:
                self.label_message = tk.Label(self, text="     Username exists     ")
                self.label_message.place(x=290, y=322)

            # Close the connection
            conn.close()
            
app = MainApp()
app.mainloop()

The change must be done when the login is correct, exactly in

self.clear_content()
 Gamecontent()

The problem is that Gamecontent opens in another window and not into the same window.

Here is the code for Gamecontent class

from tkinter import *
from random import randint
from gamedata import words, count

class Gamecontent(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.title('Word Warrior - Play')
        self.geometry("650x510")
        self.resizable(width=False, height=False)

        def next():
            global hinter, hinter_count
            # Clear the screen
            answer_label.config(text="")
            my_entry.delete(0, END)
            hint_label.config(text="")
            # Reset Hint stuff
            hinter = ""
            hinter_count = 0

            # Create random selection
            global random_word
            random_word = randint(0, count-1)
            # update label with Spanish Word
            spanish_word.config(text=words[random_word][0])

        def answer():
            if my_entry.get().capitalize() == words[random_word][1]:
                answer_label.config(text=f"Correct! {words[random_word][0]} is {words[random_word][1]}")
            else:
                answer_label.config(text=f"Incorrect! {words[random_word][0]} is not {my_entry.get().capitalize()}")

        def hint():
            global hinter_count
            global hinter

            if hinter_count < len(words[random_word][1]):
                hinter = hinter + words[random_word][1][hinter_count]
                hint_label.config(text=hinter)
                hinter_count +=1

        # Labels
        spanish_word = Label(self, text="", font=("Helvetica", 36))
        spanish_word.pack(pady=50)

        answer_label = Label(self, text="")
        answer_label.pack(pady=20)

        my_entry = Entry(self, font=("Helvetica", 18))
        my_entry.pack(pady=20)

        # Create Buttons
        button_frame = Frame(self)
        button_frame.pack(pady=20)

        answer_button = Button(button_frame, text="Answer", command=answer)
        answer_button.grid(row=0, column=0, padx=20)

        next_button = Button(button_frame, text="Next", command=next)
        next_button.grid(row=0, column=1)

        hint_button = Button(button_frame, text="Hint", command=hint)
        hint_button.grid(row=0, column=2, padx=20)

        # Create Hint Label
        hint_label = Label(self, text="")
        hint_label.pack(pady=15)

        # Run next function when program starts
        next()

        self.mainloop()

I’m stuck with this for a while and can’t move forward, I’m not even sure it’s possible with tkinter to do so.

I tried clearing the content of the window and start an instance of the second class but it opens in another window.

Asked By: lifeofsaem

||

Answers:

Change

            self.clear_content()
            Gamecontent()`

to

            self.clear_content()
            Gamecontent(self)

In gamecontent itself change

class Gamecontent(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.title('Word Warrior - Play')
        self.geometry("650x510")
        self.resizable(width=False, height=False)

to

class Gamecontent(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        #self.config(bg="white")
        self.pack(fill=BOTH, expand=True)
        parent.title('Word Warrior - Play')

This makes gamecontent to a frame which packs itself into your main app

Answered By: Ludo
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.