0

I want to script two widgets which would be stacked and I would switch from one to another with a key. Each widget would be a Frame containing several Labels. I have the following code so far (only one Label per Frame):

import Tkinter as tk
import ttk
import datetime

def main():
    # initialize root
    root = tk.Tk()
    # initialize widgets
    dash = Dashboard(root)
    notepad = Notepad(root)
    # set key actions
    root.bind('<F11>', root.lift)
    root.bind('<F1>', dash.raiseme)
    root.bind('<F2>', notepad.raiseme)
    root.mainloop()

class Dashboard(ttk.Frame):
    def __init__(self, parent):
        ttk.Frame.__init__(self, parent)  # voodoo
        self.dashframe = tk.Frame(parent)
        self.labone = tk.Label(self.dashframe, text="lab1", fg='black', bg='blue')
        self.labone.grid(row=0, column=0)

    def raiseme(self, event):
        print "raiseme dash"
        self.labone.configure(text=datetime.datetime.now())
        self.dashframe.lift()

class Notepad(ttk.Frame):
    def __init__(self, parent):
        ttk.Frame.__init__(self, parent)  # also voodoo
        self.noteframe = tk.Frame(parent)
        self.laboneone = tk.Label(self.noteframe, text="lab11", fg='white', bg='red')
        self.laboneone.grid(row=0, column=0)

    def raiseme(self, event):
        print "raiseme notepad"
        self.laboneone.configure(text=datetime.datetime.now())
        self.noteframe.lift()

if __name__ == '__main__':
    main()

Pressing F1 and F2 reach the correct routines but the only thing I get is the main window, empty. There are no errors displayed so I guess that the code runs fine (just not the way O would like to :)).

Can I achieve the switch using the skeleton above?

WoJ
  • 27,165
  • 48
  • 180
  • 345
  • Looks like there might be some useful info here: [http://stackoverflow.com/questions/11503324/how-to-switch-to-a-different-frame-in-tkinter-in-python][1] [1]: http://stackoverflow.com/questions/11503324/how-to-switch-to-a-different-frame-in-tkinter-in-python – Totem Dec 09 '13 at 23:15
  • @Totem: yes, I saw the question (and learned about `lift` from there) but it did not help. – WoJ Dec 09 '13 at 23:16
  • You haven't placed either frame anywhere with `pack` or `grid` or anything else, so… where are you expecting them to appear? – abarnert Dec 09 '13 at 23:26
  • ok, the only other thing i can think of that might help is looking into possibilities with focus_set.. – Totem Dec 09 '13 at 23:28
  • 1
    Also, why is each of your frame subclasses creating a _second_ frame on the same parent (also not placed anywhere), and then adding the label to that second frame, instead of to itself? – abarnert Dec 09 '13 at 23:28
  • abarnet is correct, no need to create those sub-frames, you just never told your Notepad or Dashboard where to appear. – Fiver Dec 09 '13 at 23:37

1 Answers1

2

There are at least two big problems with your code.

First, you're creating all these new frames, but not placing them anywhere, so they will never show up anywhere. If you have a main window with nothing placed on it, of course you will just "get the main window, empty". You need to call pack or some other layout method on any widget to get it to show up on its parent. In this case, it sounds like you want to put them both in the exact same place, so grid or place is probably what you want.

Second, your Dashboard and Notepad classes are themselves Frames, but they don't do any Frame-ish stuff; instead, they each create another, sibling Frame and attach a label to that sibling. So, even if you packed the Dashboard and Notepad, they're just empty frame widgets, so that wouldn't do any good.

If you fix both of those, I think your code does what you want:

class Dashboard(ttk.Frame):
    def __init__(self, parent):
        ttk.Frame.__init__(self, parent)  # voodoo
        self.labone = tk.Label(self, text="lab1", fg='black', bg='blue')
        self.labone.grid(row=0, column=0)
        self.grid(row=0, column=0)

    def raiseme(self, event):
        print "raiseme dash"
        self.labone.configure(text=datetime.datetime.now())
        self.lift()

class Notepad(ttk.Frame):
    def __init__(self, parent):
        ttk.Frame.__init__(self, parent)  # also voodoo
        self.laboneone = tk.Label(self, text="lab11", fg='white', bg='red')
        self.laboneone.grid(row=0, column=0)
        self.grid(row=0, column=0)

    def raiseme(self, event):
        print "raiseme notepad"
        self.laboneone.configure(text=datetime.datetime.now())
        self.lift()

However, you might also want to set a fixed size for everything; otherwise you could end up lifting the red widget and, e.g., only covering 96% of the blue one because the current time is a bit narrower than the previous one…


The code you linked to for inspiration attempted to do this:

    newFrame = tkinter.Frame(root).grid()
    newFrame_name = tkinter.Label(newFrame, text="This is another frame").grid()

That won't work, because grid returns None, not the widget. But at least it calls grid; yours doesn't even do that.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Thanks. I see that I `lift`ed the wrong elements, that's one thing (beyond the subframes which did not make sense, now that I start to understand how they work). You mention that I did not use `grid()`-- I used them but only on the `Label` elements. Now I understand that I also need the `grid()` on the frame, which does indeed makes sense. As for the fixed size - you are right, the code I gave is just a small example. Thanks again! – WoJ Dec 10 '13 at 08:44
  • As a side question: would you know what the `ttk.Frame.__init__(self, parent)` lines do? (I found this in an example but the meaning of this line escapes me) – WoJ Dec 10 '13 at 08:46
  • @WoJ: [This blog post](http://stupidpythonideas.blogspot.com/2013/12/whats-deal-with-ttkframeinitself-parent.html) attempts to explain it. If it still isn't clear, feel free to ask followup questions. (By the way, this is one of many things that gets simpler when you upgrade to Python 3.x.) – abarnert Dec 10 '13 at 19:17