0

I'm struggling with tkraise not hiding the 'bottom' frame in my app. I have two frames, one contains a Listbox and is packed to the left and the other will display options for each item in the listbox and is packed to the right. My problem is that I can see the Future page when I select General and vise versa. I copied and modified it from my working main app but I don't know what I did wrong to break it for this one.

# All settings windows and forms labels are built in here

import tkinter as tk
# from main import WinSize
from tkinter import Listbox, END, ttk


class Settings(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        # create frame for listbox and parameters area
        self.list_container = ttk.Frame(self, relief='sunken')
        self.list_container.pack(side='left', fill='y', expand=False)
        self.param_container = ttk.Frame(self)
        self.param_container.pack(side='top', fill='both', expand=True)


        self.options_list = Listbox(self.list_container, selectmode='single')

        for choice in ['General', 'Future']:
            self.options_list.insert(END, choice)


        self.okbutton = ttk.Button(self.param_container, text="OK", command= self.destroy)
        self.okbutton.grid_rowconfigure(0, weight=1)
        self.okbutton.grid_columnconfigure(0, weight=1)
        self.okbutton.grid(row=2, column=2, sticky='nsew')

        # Grid layout for Settings window
        self.options_list.grid(row=0, column=0, sticky='nsew')

        self.list_container.grid_rowconfigure(1, weight=1)
        self.list_container.grid_columnconfigure(1, weight=1)

        self.param_container.grid_rowconfigure(1, weight=1)
        self.param_container.grid_columnconfigure(1, weight=1)

        # create empty TUPLE for future frames
        self.frames = {}
        # generate calls for frames
        for F in (General, Future):
            self.page_name = F.__name__
            self.frame = F(parent=self.param_container, controller=self)
            self.frames[self.page_name] = self.frame

        self.options_list.select_set(0)
        self.options_list.bind("<<ListboxSelect>>", self.onselect)
        self.options_list.event_generate("<<ListboxSelect>>")

    # grab value of listbox selection and call show_frame
    def onselect(self, event):
        self.widget = event.widget
        self.value = self.widget.get(self.widget.curselection())
        print(self.value)
        self.show_frame(self.value)

    # show corresponding frame based on listbox selection
    def show_frame(self, page_name):
        # show a frame for the given page name
        self.frame = self.frames[page_name]
        self.frame.grid(row=0, column=1, sticky='nsew')
        self.frame.tkraise()
        print("Show Frame")


class General(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.optiontitle = ttk.Label(parent, text='General')
        self.optiontitle.grid(row=0, column=0, sticky='nsew')
        self.dirlabel = ttk.Label(parent, text='Default Save Directory')
        self.dirlabel.grid(row=1, column=1, sticky='s')


class Future(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        test1 = ttk.Label(self, text='Future')
        test1.pack()


app=Settings()
app.mainloop()

I want to say it may be something to do with my grid layout but it doesn't make sense since the two 'pages' are not coupled (or supposed to be) with each other.

Ernie Peters
  • 537
  • 1
  • 6
  • 18
  • Why are you importing from tkinter twice? you already did `import tkinter as tk` so you dont need to import anything else from tkinter. Instead just do `tk.Listbox`, `tk,END`, and for ttk you should do `import tkinter.ttk as ttk` so you can keep things simple and mostly compatible with other version of tkinter and python. – Mike - SMT Jul 20 '17 at 14:02
  • thanks for the advice @SierraMountainTech. I was following a simple tutorial on line for some of it and it taught me wrong :(. I will make a habit of writing the code like you suggested. – Ernie Peters Jul 20 '17 at 14:09
  • You could probably use `tk.ttk.widget` but the reason I recommend to do `import tkinter.ttk as ttk` is due to the fact that in python 2 the `ttk` library is separate from the tkinter library. So this way as long as everyone imports as `tk` and as `ttk`then the code can work for the most part on both python 2 and 3 without having to rework the code to much or at all in some cases. – Mike - SMT Jul 20 '17 at 14:18
  • btw `self.frames = {}` is not an empty tuple its an empty dictionary. – Mike - SMT Jul 20 '17 at 14:34

2 Answers2

1

I solved this issue through another problem that I was able to work out with some help from others. Refer to this → Frames not stacking on top of each other in tkinter question as it has two great answers which easily allow to incorporate grid_forget() and/or pack_forget() as suggested by @jasonharper.

martineau
  • 119,623
  • 25
  • 170
  • 301
Ernie Peters
  • 537
  • 1
  • 6
  • 18
0

You aren't doing anything to actually hide the other page; you're just layering the new page on top of it, which isn't going to look right unless they occupy exactly the same screen area.

Even if they did, this still isn't a workable approach, since the widgets in the hidden page are still active. In particular, if it had any Entry or Text fields, they could still have (or gain) keyboard focus, so anything the user types might mysteriously end up in a field they can't even see at the moment.

You should call .grid_forget() on the previous page when showing the new one. Or, perhaps easier, call .grid_forget() on all pages before calling .grid() on the new one (it doesn't hurt to call this on a widget that isn't currently shown).

jasonharper
  • 9,450
  • 2
  • 18
  • 42
  • when using `.grid_forget()`. Will it forget the values entered in texboxes the moment I go to another page/widget or will the values be retained when I go back to the previous page?. I would have to save those values somewhere if the first is true. – Ernie Peters Jul 20 '17 at 14:52
  • @ErniePeters: You can test it yourself and find out :P. I have not used `grid_forget()` myself but judging by the name its only removing the placement of widgets and not the content of said widget. And according to the documentation I just googled [here](http://effbot.org/tkinterbook/grid.htm#Tkinter.Grid.grid_forget-method) my guess is accurate. – Mike - SMT Jul 20 '17 at 15:48