目标
利用toplevel,重写根(root)窗体,将显示图片的功能显示在一个toplevel弹出窗口中。
- 重写root;
- 修改HelloTkinter,封装一个弹出窗体;
- 整体代码打个标签:V1.2.2。
操作如视频所示:
【自由生长的python】利用toplevel做一个弹窗
总结
在实现目标的过程中,主要遇到问题就是在弹出toplevel时,隐藏根窗体;在退出toplevel窗体时,显示根窗体。可以注意一下main.py文件中这几个函数的调用,:
self.root.withdraw()
myImageViewer = MyImageViewer(self.root)
self.root.wait_window(myImageViewer.top)
self.root.deiconify()
self.root.update()
最终可通过可以使用下面四行命令,体验一下程序运行的效果
git clone https://github.com/kamigo2018/myTkinter.git
cd myTkinter
git checkout V1.2.2
python main.py
简单说一下要做啥
1、设计根(root)窗体
根窗体上就放上几个按键,提供不同的功能。其中除了显示图片这个功能,其他功能还没实现。“UDP程序”和“TCP程序”准备后面分别实现两个例子,简单展示一下socket通讯。“还没想好”,是真没想好还要干啥。
2、显示图片功能
没错,看起来和原来的窗体没啥区别。其实真的没有太大的区别,就是将原来的窗体在一个新的toplevel组件中显示出来了,没啥新东西。
再说一下都是咋做的
1、根窗体
新建main.py ,模仿HelloTkinter,为这个新应用创建 Application类。
- create函数
在Application类中,创建create函数,用来展示整个界面。这个根窗口设计成宽度固定,长度可变,安放四个按钮,一个退出按钮的样子:
def create(self):
'''
将主界面设计成一个竖条形状,分成两个区域:自主研发功能区+退出按键区。
自主研发功能区:目前里面放置多个功能按键,后续按下每一个按键弹出一个界面。
退出按键区:就放置一个按键,用来退出。
'''
self.frameFont = tkFont.Font(family='微软雅黑',size = '16')
# 整个区域划分成两个窗体,一个用来放功能按键,一个专门用来放退出按键。
# 我还想给这个中间加条线。现在还不会。不过应该可以加,如何能让他明显一点?
self.funcFrame = tk.Frame(self.root);
self.separatorLine = ttk.Separator(self.root,orient='horizontal',style='red.TSeparator')
self.quitFrame = tk.Frame(self.root);
# ==start==
# 设置上面两部分区域的框架,容纳其他显示在顶层页面的组件
self.funcFrame.grid(row = 0, column=0, sticky='NWES')
self.separatorLine.grid(row = 1, column=0, sticky='NWES') # 这条分割线没有显示出来,没起作用?
self.quitFrame.grid(row = 2, column=0, sticky='NWES')
tk.Grid.rowconfigure(self.root,0,weight=15)
# tk.Grid.rowconfigure(self.root,1,weight=15) #还是看不到这条线
tk.Grid.rowconfigure(self.root,2,weight=1) # 甚至应该考虑这个窗体是否应该固定大小
tk.Grid.columnconfigure(self.root,0,weight = 1)
# ==end==
# 实例化在funcFrame里面的4个函数按键
self.button1 = tk.Button(self.funcFrame,text='显示图片',font=self.frameFont, command = self.func1)
self.button2 = tk.Button(self.funcFrame,text='UDP程序',font=self.frameFont, command = self.func2)
self.button3 = tk.Button(self.funcFrame,text='TCP程序',font=self.frameFont, command = self.func3)
self.button4 = tk.Button(self.funcFrame,text='还没想好',font=self.frameFont, command = self.func4)
# ==start==
# 设置以上4个按键的位置
self.button1.grid(row=0,column=0,rowspan=1,sticky='NWES')
self.button2.grid(row=1,column=0,rowspan=1,sticky='NWES')
self.button3.grid(row=2,column=0,rowspan=1,sticky='NWES')
self.button4.grid(row=3,column=0,rowspan=1,sticky='NWES')
tk.Grid.rowconfigure(self.funcFrame,0,weight=1)
tk.Grid.rowconfigure(self.funcFrame,1,weight=1)
tk.Grid.rowconfigure(self.funcFrame,2,weight=1)
tk.Grid.rowconfigure(self.funcFrame,3,weight=1)
tk.Grid.columnconfigure(self.funcFrame,0,weight=1)
# ==end==
# 实例化一个退出按键
self.buttonQuit = tk.Button(self.quitFrame,text='退 出',font=self.frameFont)
self.buttonQuit.config(bg='gray',fg='black',command=self.quit)
# ==start==
# == 设置quitFrame中按键的大小和位置 ==
self.buttonQuit.grid(row=0,column=0,sticky='NWES')
tk.Grid.rowconfigure(self.quitFrame,0,weight=1)
tk.Grid.columnconfigure(self.quitFrame,0,weight=1)
# ==end==
pass
和之前一样,还是使用grid布局方式,组件自适应容器窗体的形变。
- 按键功能函数
最简单的退出功能,在按下“退出”键时触发。就是调用root窗体的destroy函数。遗留一个问题:虽然 root.quit() 和 root.destroy() 两个函数都可以实现退出功能,但是这两个功能有什么区别?我没有深究,这个当做一个问题,先留下来。
def quit(self):
# self.root.quit()
self.root.destroy() # 这两个有什么区别?
比较麻烦的“显示图片”功能。这里新建了一个MyImageViewer的实例,通过这个实例新建了一个toplevel的组件,当做新的容器,显示图片。在创建这个窗体之前,记录了原始根窗体的大小,位置信息。并利用 root.withdraw() 和 root.deiconify(), root.update() 隐藏和显示根窗体。利用 wait_window(myImageViewer.top) 展示“显示图片”窗体。
def func1(self):
# 这里需要隐藏主界面,弹出对应功能界面。操作完成后,退出功能界面,回到主界面。
# 保存原始窗体的大小,参考:
# https://www.daniweb.com/programming/software-development/threads/322818/tkinter-window-size
# https://www.imooc.com/wenda/detail/608947
# 主窗体的宽高尺寸
winWidth = self.root.winfo_width()
winHeight = self.root.winfo_height()
# 主窗体在屏幕的位置
screenX = self.root.winfo_x()
screenY = self.root.winfo_y()
self.root.withdraw()
myImageViewer = MyImageViewer(self.root)
self.root.wait_window(myImageViewer.top)
self.root.deiconify()
self.root.update()
self.root.geometry(("{}x{}+{}+{}").format(winWidth,winHeight,screenX,screenY))
其他函数,例如func2,没有实质内容,就不说了。
def func2(self):
pass
#print("UDP")
2、显示图片
之前的版本中,显示图片的功能,作为在根窗体中的主要功能,通过几个frame直接展示出来。这次,通过toplevel组件,重新组织这些frame框体。由于是重新组织,不是开发,所以相对来说就是复制并修改原有的的frame组件代码,主要修改内容,就是修改frame的父容器。
在HelloTkinter.py中,新建 MyImageViewer 类,基本上和原有的Appcliation很像。
看一下初始化函数,这里看到,我们实例化了一个toplevel组件,命名为top。top的父容器就是我们的根容器。
def __init__(self,master):
# 这里的 master 应该是根应用的tk.Tk()组件。
# 而这个类要产生一个toplevel组件,用来展示一个单独的功能窗体。
self.master = master
self.top = tk.Toplevel(self.master)
tk.Grid.rowconfigure(self.top,0,weight=1)
tk.Grid.columnconfigure(self.top,0,weight=1)
self.imageResizeRatio = 100
self.imageFlag = 0
self.create()
之后,这个top就作为显示一个新的父窗体,容纳我们的的菜单栏,输入窗体,显示窗体。
def create(self):
pass
# 干什么?显示图片,有菜单栏,有展示窗体,有输入窗体。
# 创建菜单栏
self.createMenu()
# 创建显示文字的text widget 的Frame
self.createShowResultFrame()
# 创建输入文字的Frame
self.createInputFrame()
def createMenu(self):
self.menuBar = tk.Menu()
# menuBar的父窗体就变成了top。
self.top.config(menu=self.menuBar)
... ... # 具体功能和之前版本中的一样,所以这里就不展示了。
打上标签
相比V1.2.1,程序有了新的根窗体,所以算是一个比较大的改变,这里打上标签:V1.2.2。