stetim94
stetim94

Reputation: 64

displaying information on another frame? (tkinter python)

so there is this stackoverflow question:

Switch between two frames in tkinter

Which looks like a beautiful basis for building an application. But what if on startPage i want to have multiply buttons, and display the appropriate data on PageOne? Here is my attempt:

import tkinter as tk
from functools import partial

characters = {"character1": "abc", "character2": "def", "character3": "ghi", "character4": "jkl", "character5": "mnp", "character6": "qrs" }

class AdventureGame:
    ''' controller for managiging frames '''
    def __init__(self, master):
        self.master = master
        self.frames = {}
        for F in (StartGame,ShowCharacters,CharacterDetail):
            frame = F(parent=master, controller=self)
            self.frames[F.__name__] = frame
            frame.grid(row=0, column=0, sticky="nsew")
        ''' rais the first frame '''
        self.raise_frame("StartGame")

    def raise_frame(self,page_name):
        ''' raise a frame '''
        frame = self.frames[page_name]
        frame.tkraise()

    def lower_frame(self,page_name):
        ''' lower a frame '''
        frame = self.frames[page_name]
        frame.lower()

class StartGame(tk.Frame):
  ''' introduction screen of the game '''
  def __init__(self, parent, controller):
    super(StartGame,self).__init__(parent)
    self.controller = controller
    ''' introduction text '''
    tk.Label(self, text="welcome to this game").grid()
    tk.Button(self, text="next", command=lambda: controller.raise_frame("ShowCharacters")).grid()

class ShowCharacters(tk.Frame):
  ''' main frame, overview of all pokemon '''
  def __init__(self, parent, controller):
    super(ShowCharacters,self).__init__(parent)
    self.controller = controller
    for row, character in enumerate(characters):
      name_label = tk.Label(self, text=characters[character])
      name_label.grid(row=row,column=0)
      info_button = tk.Button(self, text="view info", command=partial(self.switch,character))
      info_button.grid(row=row,column=1)

  def switch(self, character):
    test = self.controller.raise_frame("CharacterDetail")

class CharacterDetail(tk.Frame):
    ''' detail view of pokemon '''
    def __init__(self, parent, controller):
        super(CharacterDetail,self).__init__(parent)
        self.controller = controller
        tk.Button(self, text="back", command=lambda: controller.lower_frame("CharacterDetail")).grid()

     # somehow display characters name here
    def showdetail(self):
        tk.Label(self, text="test").grid()

def main():
    root = tk.Tk()
    app = AdventureGame(root)
    root.mainloop()
main()

It feels like the the key is in the controller, as explained here:

How to get variable data from a class

It just feels like i am missing something, does someone have an idea? Or am i thinking in the wrong direction all together?

If i try to show the detail:

def switch(self, character):
    test = self.controller.raise_frame("CharacterDetail")
    CharacterDetail.showdetail(self)

it shows up at the ShowCharacters frame rather then the CharacterDetail frame

I guess because self is the frame, which is self from ShowCharacters

I need to do something with the controller, but my mind just goes blank

So now i pass information to the controller:

import tkinter as tk
from functools import partial

characters = {"character1": "abc", "character2": "def", "character3": "ghi", "character4": "jkl", "character5": "mnp", "character6": "qrs" }

class AdventureGame:
    ''' controller for managiging frames '''
    def __init__(self, master):
        self.master = master
        self.frames = {}
        for F in (StartGame,ShowCharacters,CharacterDetail):
            frame = F(parent=master, controller=self)
            self.frames[F.__name__] = frame
            frame.grid(row=0, column=0, sticky="nsew")
        self.app_data = {"test": "test"}
        ''' rais the first frame '''
        self.raise_frame("StartGame")

    def raise_frame(self,page_name):
        ''' raise a frame '''
        frame = self.frames[page_name]
        frame.tkraise()

    def lower_frame(self,page_name):
        ''' lower a frame '''
        frame = self.frames[page_name]
        frame.lower()

class StartGame(tk.Frame):
  ''' introduction screen of the game '''
  def __init__(self, parent, controller):
    super(StartGame,self).__init__(parent)
    self.controller = controller
    ''' introduction text '''
    tk.Label(self, text="welcome to this game").grid()
    tk.Button(self, text="next", command=lambda: controller.raise_frame("ShowCharacters")).grid()

class ShowCharacters(tk.Frame):
  ''' main frame, overview of all pokemon '''
  def __init__(self, parent, controller):
    super(ShowCharacters,self).__init__(parent)
    self.controller = controller
    for row, character in enumerate(characters):
      name_label = tk.Label(self, text=characters[character])
      name_label.grid(row=row,column=0)
      info_button = tk.Button(self, text="view info", command=partial(self.switch,character))

      info_button.grid(row=row,column=1)

  def switch(self, character):
    test = self.controller.raise_frame("CharacterDetail")
    CharacterDetail.example(self)

class CharacterDetail(tk.Frame):
    ''' detail view of pokemon '''
    def __init__(self, parent, controller):
        super(CharacterDetail,self).__init__(parent)
        self.controller = controller
        tk.Button(self, text="back", command=lambda: controller.lower_frame("CharacterDetail")).grid()
    def example(self):
        tk.Label(self, text=self.controller.app_data["test"]).grid()


def main():
    root = tk.Tk()
    app = AdventureGame(root)
    root.mainloop()
main()

the label is still on the wrong frame, how can i get access to the right self so i can add the label to the right frame?

Upvotes: 0

Views: 1474

Answers (1)

acw1668
acw1668

Reputation: 46678

As you call CharacterDetail.example(self) in function switch(...) of class ShowCharacters, self will be class ShowCharacters. Therefore the label created in function example(self) of class CharacterDetail will be in ShowCharacters frame.

Try:

  • return the raised frame in function raise_frame(...) of class AdventureGame:

    def raise_frame(self, page_name):
        frame = self.frames[page_name]
        frame.tkraise()
        return frame   # return the raised frame
    
  • modify function switch(...) of class ShowCharacters:

    def switch(self, character):
        frame = self.controller.raise_frame("CharacterDetail")
        frame.example()
    

Upvotes: 1

Related Questions