python3 tkinter页面跳转(尽量松耦合?

tkinter简介:

tkinter是python3自带的GUI模块,可以很方便地生成一个exe/app,windows和macOS都适用。

业务目标:

一个有三级页面的程序,二级页面可以返回一级页面,三级页面可以返回二级页面

技术目标:

尽量松耦合,一级页面一直存在不被销毁,除非退出程序

页面结构

main page
- month page
- month page 2
- version page
- version page 2

最后的效果:

tkinter demo动图

程序结构

# 程序入口,一个自定义的application
if __name__ == '__main__':

    pm = PageManager()
    pm.mainloop()

# 自定义的application类,继承自tkinter.Tk
# 参照大多数教程root = tkinter.Tk()
class PageManager(tkinter.Tk):
    """
        这是一个application
    """
    def __init__(self):
        super().__init__()
        self.title("App test")
        self.geometry("200x100")
        self.iconbitmap()
        self.pages = []
        p = MainPage(self)  # 主要功能:初始化主页,永远都在list的第一个
        self.pages.append(p)
        print("after init, pages length: ", len(self.pages))

# 自定义的主页类,继承自tkinter.Frame
# 参照大多数教程frame = Frame(root, ....)
class MonthlyPage(Frame):
    def __init__(self, win):
        super().__init__(win)
        self.win = win
        Label(self, text="this is page month").pack()
        Button(self, text="month page TWO", command=self.go_to_month_two).pack()
        Button(self, text="go back", command=self.go_back).pack()
        print("this is month page, now the pages: ", len(self.win.pages))
        self.pack()

    def go_to_month_two(self):
        print("month page now go to month page TWO...")
        self.forget()   # 本页面没有销毁,只是隐藏,要不然会窗口中既有month page 也有month page 2
        p = MonthlyPageTwo(self.win)    # 让month page 2 出现在窗口中,主要就是pack方法
        self.win.pages.append(p)    # 更新窗口的page_list,像出栈入栈一样展示frames

    def go_back(self):
        self.win.pages.pop()
        self.win.pages[-1].pack()   # 返回到上一页
        self.destroy()  # 那当前页就可以销毁了

# 和month page 基本一样的month page 2
class MonthlyPageTwo(Frame):
    def __init__(self, win):
        super().__init__(win)
        self.win = win
        Label(self, text="this is page month TWO").pack()
        Button(self, text="go back", command=self.go_back).pack()
        print("this is month page TWO, now the pages: ", len(self.win.pages))
        self.pack()

    def go_back(self):
        self.win.pages.pop()
        self.win.pages[-1].pack()
        self.destroy()

# version page就更是copy month page了,省略
待处理的

原来PageManager.py的pages是类属性,考虑到每个frame都共用同一个PageManager类。
但实现起来发现,获取len(pages)时需要指定类名而不是实例名,然后就发生里循环import的报错。
临时解决方法:把类属性改成了实例属性。
**最终待解决:**弄清楚怎么解决循环import问题

总结

别看最后代码不多,这结构思考了好久,方案翻来覆去想不通,最后还是画图+code能解决问题!

plan A:

一个PageManager管理所有页面的show和hide,这样的话,一级页面调用二级页面是没问题,但二级页面哪里还能去调用PageManager的show和hide呢? FAIL!

plan B:

顺序实现,别管什么结构先,最后看看写出来的东西再考虑优化的方向。 PASS!

从MainPage写完2个二级页面,发现二级页面很雷同,可以提出来,只是要考虑实例化时传参的问题——Frame实例化需要传入窗口/app这个参数,而实例化控件只需传入Frame这个参数,无形中已经分好层次了,哪些对象可以写在一个类中。
即Frame和控件组合,窗口/app独立成一个参数传给Frame。

# PageManager.py
# 把自己作为参数,实例化Frame
p = MainPage(self)

# MonthPage.py
class MonthlyPage(Frame):
    def __init__(self, win):
        super().__init__(win)
        self.win = win

设置PageManager最主要的目的就是想用上page_list这个数据结构,因为觉得这些页面叠加又去掉,很像出栈入栈。
等到页面间的关系复杂了,也许能派上用场。

  • 4
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Tkinter中,可以使用Tkinter的Toplevel小部件来创建新的窗口,同时使用协议方法(protocol method)来捕获窗口关闭事件。可以使用Toplevel小部件来实现页面跳转的效果。 下面是一个简单的示例代码,实现了两个页面之间的跳转: ``` import tkinter as tk class Page1(tk.Frame): def __init__(self, master=None): super().__init__(master) self.master = master self.pack() self.create_widgets() def create_widgets(self): self.hi_there = tk.Button(self) self.hi_there["text"] = "Go to Page 2" self.hi_there["command"] = self.go_to_page2 self.hi_there.pack(side="top") def go_to_page2(self): self.master.switch_frame(Page2) class Page2(tk.Frame): def __init__(self, master=None): super().__init__(master) self.master = master self.pack() self.create_widgets() def create_widgets(self): self.hi_there = tk.Button(self) self.hi_there["text"] = "Go to Page 1" self.hi_there["command"] = self.go_to_page1 self.hi_there.pack(side="top") def go_to_page1(self): self.master.switch_frame(Page1) class MyApp(tk.Tk): def __init__(self): super().__init__() self.title("My App") self.geometry("200x100") self.switch_frame(Page1) def switch_frame(self, frame_class): new_frame = frame_class(self) if self._frame is not None: self._frame.destroy() self._frame = new_frame self._frame.pack() if __name__ == "__main__": app = MyApp() app.mainloop() ``` 在这个示例中,有两个页面:Page1和Page2。每个页面都是Tkinter的Frame小部件的子类,Frame小部件是一个容器,可以包含其他小部件。 MyApp是一个Tkinter的Tk小部件的子类,Tk小部件是一个顶层窗口,是整个GUI应用程序的根。 在MyApp的构造函数中,创建了Page1的实例,并调用switch_frame方法,将其显示在窗口中。 在switch_frame方法中,创建了新的页面实例,并将其显示在窗口中。如果之前存在其他页面实例,会先销毁它。 在Page1和Page2的构造函数中,创建了一个按钮,点击按钮可以跳转到另一个页面。 在按钮的回调函数中,调用了MyApp的switch_frame方法,将页面切换到另一个页面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值