tkinter简介:
tkinter是python3自带的GUI模块,可以很方便地生成一个exe/app,windows和macOS都适用。
业务目标:
一个有三级页面的程序,二级页面可以返回一级页面,三级页面可以返回二级页面
技术目标:
尽量松耦合,一级页面一直存在不被销毁,除非退出程序
页面结构
main page - month page - month page 2 - version page - version page 2
最后的效果:
程序结构
if __name__ == '__main__':
pm = PageManager()
pm.mainloop()
class PageManager(tkinter.Tk):
"""
这是一个application
"""
def __init__(self):
super().__init__()
self.title("App test")
self.geometry("200x100")
self.iconbitmap()
self.pages = []
p = MainPage(self)
self.pages.append(p)
print("after init, pages length: ", len(self.pages))
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()
p = MonthlyPageTwo(self.win)
self.win.pages.append(p)
def go_back(self):
self.win.pages.pop()
self.win.pages[-1].pack()
self.destroy()
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()
待处理的
原来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。
p = MainPage(self)
class MonthlyPage(Frame):
def __init__(self, win):
super().__init__(win)
self.win = win
设置PageManager最主要的目的就是想用上page_list这个数据结构,因为觉得这些页面叠加又去掉,很像出栈入栈。 等到页面间的关系复杂了,也许能派上用场。
|