0

I am trying to create Python 3.7+ Tkinter app with another frame which can be brought up by clicking a button:

Sentdex example

Stackoverflow example

I create a class with Tkinter (ThemedTk) and want to create few classes with ttk.Frame. Buttons will switch between the Frames. My issue right now - I can't make the frame to resize and stick 'nesw' to the main root Class. I'm assuming I'm doing something wrong with ttk.Frame but I can't understand the issue. I added

self.grid(row=0, column=0)
self.rowconfigure(0, weight=3)
self.columnconfigure(0, weight=3)

but it doesn't seem to help... The entire code:

import tkinter as tk
from tkinter import ttk
from ttkthemes import ThemedTk

class MainApp(ThemedTk):
    def __init__(self):
        ThemedTk.__init__(self)
        self.set_theme('equilux', themebg=True)
        self.title('Test App')
        self.style = ttk.Style(self)
        self.DESKTOP_WIDTH = self.winfo_screenwidth()
        self.DESKTOP_HEIGHT = self.winfo_screenheight()
        self.WIDTH = int(self.DESKTOP_WIDTH / 4)
        self.HEIGHT = int(self.DESKTOP_HEIGHT / 2.5)
        self.geometry(f'{self.WIDTH}x{self.HEIGHT}+{int(self.DESKTOP_WIDTH / 3)}+{int(self.DESKTOP_HEIGHT / 4)}')
        self.minsize(width=self.WIDTH, height=self.HEIGHT)
        self._frame = None
        self.switch_frame(MainLogin)

    def switch_frame(self, frame_class):
        """Destroys current frame and replaces it with a new one."""
        new_frame = frame_class(self)
        if self._frame is not None:
            self._frame.destroy()
        self._frame = new_frame
        self._frame.grid(row=0, column=0)


class MainLogin(ttk.Frame):
    def __init__(self, master):
        ttk.Frame.__init__(self, master, padding=(5, 5, 5, 5), borderwidth=10, relief='ridge', sticky='nesw')
        self.grid(row=0, column=0)
        self.rowconfigure(0, weight=3)
        self.columnconfigure(0, weight=3)
        self.master = master
        self.userid = tk.StringVar()
        self.password = tk.StringVar()
        self.remember = tk.StringVar()

        self.frame_login = ttk.Frame(self, padding=(10, 10, 10, 10), borderwidth=2, relief='ridge')

        self.label_welcome = ttk.Label(self.frame_login, text='Open App')
        self.label_user = ttk.Label(self.frame_login, text='User ID:')
        self.entry_user = ttk.Entry(self.frame_login, textvariable=self.userid)
        self.label_password = ttk.Label(self.frame_login, text='Password:')
        self.entry_password = ttk.Entry(self.frame_login, textvariable=self.password, show='*')
        self.check_remember = ttk.Checkbutton(self.frame_login, text='Remember me', variable=self.remember, onvalue='yes', offvalue='no')
        self.button_login = ttk.Button(self.frame_login, text='Login', command=lambda: MainLogin.login(self.userid, self.password))
        self.button_register = ttk.Button(self.frame_login, text='Register', command=self.register)

        self.grid_widgets()
        self.resize_widgets()

    def grid_widgets(self):
        self.frame_login.grid(row=0, column=0, sticky='nesw')
        self.label_welcome.grid(row=0, column=0, columnspan=2, pady=30, sticky='n')
        self.label_user.grid(row=1, column=0, padx=10, pady=5, sticky='e')
        self.entry_user.grid(row=1, column=1, padx=10, pady=5, sticky='w')
        self.label_password.grid(row=2, column=0, padx=10, pady=5, sticky='e')
        self.entry_password.grid(row=2, column=1, padx=10, pady=5, sticky='w')
        self.check_remember.grid(row=3, column=0, columnspan=2, pady=5, sticky='n')
        self.button_login.grid(row=4, column=0, padx=10, pady=5, ipadx=30, sticky='e')
        self.button_register.grid(row=4, column=1, padx=10, pady=5, ipadx=30, sticky='w')

    def resize_widgets(self):
        self.columnconfigure(0, weight=3)
        self.rowconfigure(0, weight=3)
        self.frame_login.columnconfigure(0, weight=3)
        self.frame_login.columnconfigure(1, weight=3)

    @staticmethod
    def login(userif, password):
        print('Login button pressed')

    def register(self):
        print('Register button pressed')



if __name__ == '__main__':
    root = MainApp()
    root.mainloop()
  • _" i'm getting errors (wm_grid() got an unexpected keyword argument 'row')"_ - Nowhere in your code do you call `wm_grid`. Please [edit] your question to include the actual error. – Bryan Oakley Dec 02 '19 at 20:33
  • I updated the code with error. I'm getting different errors depending how and where I plug ThemedTk. As is right now the error is: "TypeError: create() argument 1 must be str or None, not Frame". If I replace tk.Tk.__init__ to ttk.Frame.__init__(self, parent) (as suggester here: https://stackoverflow.com/questions/36532433/typeerror-must-be-str-or-none-not-frame) I get "wm_grid() got an unexpected keyword argument 'row'" – user_unknown Dec 02 '19 at 21:25
  • Please [edit] your question to include the error. Code in the comment section is impossible to read. – Bryan Oakley Dec 02 '19 at 21:35
  • I am sorry... I updated my post. – user_unknown Dec 03 '19 at 02:09
  • Your code runs without error for me. – Bryan Oakley Dec 03 '19 at 02:19
  • That is correct. But if you maximize the window to fullscreen the frame and the contents of the frame won't scale/stick='nsew' even though I thought it should... – user_unknown Dec 03 '19 at 05:13
  • That has nothing to do with the theming. You simply haven't set the code up to expand. – Bryan Oakley Dec 03 '19 at 05:47
  • I cannot figure out how to do rowconfigure and columnconfigure for that frame created from class, so that it scales... – user_unknown Dec 03 '19 at 17:23

1 Answers1

0

Since you only ever have a single frame in the root window at any one time, the simplest solution is to use pack instead of grid, since you don't have to worry about configuring rows and columns.

def switch_frame(self, frame_class):
    """Destroys current frame and replaces it with a new one."""
    new_frame = frame_class(self)
    if self._frame is not None:
        self._frame.destroy()
    self._frame = new_frame
    self._frame.pack(fill="both", expand=True)

With that small change, the MainLogin frame will fill the window.

If you prefer using grid, you can replace the call to pack in the above code with this:

self._frame.grid(row=0, column=0, sticky="nsew")
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685