首页 > 解决方案 > Tkinter pages updated from separate files

问题描述

Using the below code originally posted here how can i use a 4th module with the PageList() command and a new page class below it to display it in my WindowHandler() class? through other research i believe you would have to stop using Windowhandler() as an instance of the main application class.

The goal of this is to have the stacked frames in different files while each file can update the frames={} list without any having to add it in the main class. a similar example is given here for different pages but the call to those pages must still be added within the main class.

Nav.py

import tkinter as tk
from Page import PageList
import Mypages

class Windowhandler(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand= True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        PageList("Page1", container, self, Mypages.PageOne)
        PageList("Page2", container, self, Mypages.PageTwo)
        self.show_frame("Page1")

    def show_frame(self, cont):
        frameref = PageList.frames[cont]
        print(frameref)
        frameref.tkraise()



app = Windowhandler()
app.mainloop()

Page.py

class PageList():
frames = {}
def __init__(self, name, parent, cont, ref):
    self.frames[name] = ref(parent=parent, controller=cont)

Mypages.py

    import tkinter as tk

    class PageOne(tk.Frame):
        def __init__(self, parent, controller):
            this = tk.Frame.__init__(self, parent)
            label = tk.Label(this, text="Welcome to Page 1")
            label.pack(pady=10, padx=10)

            button1 = tk.Button(this, text="Back to Home",
                        command=lambda: controller.show_frame("Page2"))
            button1.pack()

    class PageTwo(tk.Frame):
        def __init__(self, parent, controller):
            this = tk.Frame.__init__(self, parent)
            label = tk.Label(this, text="Welcome to Page 2")
            label.pack(pady=10, padx=10)

            button1 = tk.Button(this, text="Back to Home",
                        command=lambda: controller.show_frame("NewPage"))
            button1.pack()

Psuedo.py

import tkinter as tk
import Nav

PageList("NewPage", Nav.container, WindowHandler, NewPage)

class NewPage(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        btn1 = Nav(self, text="A Button" command=lambda: Controller.show_frame("Page1"))
        btn1.pack(pady=(10, 4))

标签: pythonpython-3.xtkinter

解决方案


下面的代码是我针对上述问题设法提出的,每个帧都存储在子文件夹中的不同文件中,尽管它是使用 importlib 加载的,因为这是我的应用程序所需要的。

addnav这是通过在 Main.py 文件调用的每个文件中Dstore()都有一个通用函数来实现的关于子文件。


主文件

from os import listdir
from importlib import import_module
from Resource import *


# Create our main window under the Windowhandler class.
class Windowhandler(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        tk.Tk.title(self, "Stacked frames + Stacked window with dynamic imports")
        tk.Tk.geometry(self, "800x800")
        tk.Tk.state(self, "zoomed")

    # Used for displaying stacked frames from frames list in Resource.py
    def show_frame(self, cont):
        frame = Addnav.frames[cont]
        frame.tkraise()


# Find all modules inside module subfolder, import and return list of references.
def importscript(**kwargs):
    kwargs["pdir"] = kwargs.get("pdir", "/Users/Main/PycharmProjects/Plugin-Stacked-Frames/Modules")
    pdir = kwargs["pdir"]
    mlist = {}

    for fi, file in enumerate(listdir(pdir)):
        if file.endswith(".py") and file != "__init__.py":
            module = import_module("Modules." + file.strip(".py"))
            module.Dstore()
            notify = module.Dstore.Info
            print("Imported " + notify["name"])
            mlist[fi] = module
    return mlist


# This is our root menu that has a button for each sub menu of our sub files.
class MenuHome(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent, bg="white")
        tk.Label(self, text="Root Menu").pack(pady=(20, 5))
        # Enumerate through frames and add a button object referenced to each sub files menu.
        for idx, fref in enumerate(Addnav.frames):
            sinfo = sub[idx].Dstore.Info
            btn = tk.Button(self, text=sinfo["name"], command=lambda fref=fref: controller.show_frame(fref))
            btn.pack()


sub = importscript()
app = Windowhandler()

# Create 2 containers 1 for the menu 1 for the main workspace.
container = tk.Frame(app)
container.pack(side="left", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)

for N in sub:
    pref = sub[N].Dstore.Info
    sub[N].addnav(pref["reference"], container, app)

Addnav("MenuHome", container, app, MenuHome)
Windowhandler.show_frame(container, "MenuHome")

app.mainloop()

Subfile1.py(放置在名为 Modules 的子文件夹中)

from Resource import *


# For getting information about the individual subfile.
class Dstore():
    Info = {}
    def __init__(self):
        self.Info["reference"] = "Menu1"
        self.Info["name"] = "Sub Menu 1"


# Calls the shared resource Addnav function to add the menu.
def addnav(name, container, app):
    Addnav(name, container, app, Menu1)


# The menu class for this file.
class Menu1(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent, bg="blue")
        tk.Label(self, text="Welcome to subfile menu 1").pack(pady=(20, 5))
        btn1 = tk.Button(self, text="Home", command=lambda: controller.show_frame("MenuHome"))
        btn1.pack()
        btn2 = tk.Button(self, text="Subfile menu 2", command=lambda: controller.show_frame("Menu2"))
        btn2.pack()

Subfile2.py(放置在名为 Modules 的子文件夹中)

from Resource import *


# For getting information about the individual subfile.
class Dstore():
    Info = {}
    def __init__(self):
        self.Info["reference"] = "Menu2"
        self.Info["name"] = "Sub Menu 2"


# Calls the shared resource Addnav function to add the menu.
def addnav(name, container, app):
    Addnav(name, container, app, Menu1)


# The menu class for this file.
class Menu1(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent, bg="red")
        tk.Label(self, text="Welcome to subfile 2 menu").pack(pady=(20, 5))
        btn1 = tk.Button(self, text="Home", command=lambda: controller.show_frame("MenuHome"))
        btn1.pack()
        btn2 = tk.Button(self, text="Subfile Menu 1", command=lambda: controller.show_frame("Menu1"))
        btn2.pack()

资源.py

import tkinter as tk


class Addnav:
    frames = {}

    def __init__(self, name, parent, cont, ref):
        self.frames[name] = ref(parent=parent, controller=cont)
        self.frames[name].grid(row=0, column=0, sticky="nsew")

用于使视觉明显的颜色,请注意我不是 python 大师,在这个其他功能代码中可能有十几个或更多错误,请评论编辑。


推荐阅读