在tkinter窗口中实现窗口嵌套,在一定程度上减少了桌面窗口复杂程度,可以给电脑操作系统带来较为整洁的桌面环境。父窗口的内部功能字窗口,可以嵌套在父窗口中。
虽然tkinter本身没有这样组件或功能,但我们可以进行一定程度的拓展。
实现tkinter嵌套窗口的方式有很多,一下是常见的三种:
根据这三种方法的优劣取舍,这篇文章主要讲解第三种方法,拓展frame。
窗口最主要的部分是标题栏,因此我们先要实现标题栏的功能。
在编写代码之前,先想想那些功能不需要:
1、缩小键(缩小了怎么显示?当然,你可以建立一个任务栏)
2、图标(嵌套窗口只是功能窗口,图标不重要)
现在,我们减少了两个功能和十几行代码可以开工了。
为了方便窗口中再加组件,我们使用frame作为底层。
from tkiner import Button as tkButton,Tk,Frame,Label#...
#...
class ChildFrame(Frame):
'''
这是一个建立在Frame之上的子窗口控件
该子窗口可以嵌入tkinter父窗口,但建议是在窗口而不是在控件中
子窗口可以移动也可以不移动,通过属性设定来改变子窗口的状态
需要注意的是,在内嵌子窗口导入控件时,注意起始高度为32
因为组件限制,ChildFrame只能够实现真正窗口的一小部分功能
'''
def __init__(self,root,title_color,title='title',color='#f0f0f0'):
self.root=root
super().__init__(root,bg=color)#底层
self.title=title
self.tc=title_color
self.titlebar=Frame(self,bg=self.tc)#标题栏
Label(self.titlebar,text=self.title,bg=self.tc,fg='white').place(x=5,y=5)
self.conbar=Frame(self.titlebar,bg=self.tc)
self.conbar.pack(side='right')#工具栏
self.desb=tkButton(self.conbar,text='×',font=('宋体',15),bg=self.tc,fg='white',activeforeground='white',activebackground='red',relief='flat',command=self.destroy)
self.desb.pack(side='right')#关闭按钮
self.desb.bind('' ,lambda event:self.desb.configure(background='red'))
self.desb.bind('' ,lambda event:self.desb.configure(background=self.tc))#当鼠标划过时有红色样式
self.expandb=tkButton(self.conbar,text='□',font=('宋体',15),fg='white',bg=self.tc,activeforeground='white',activebackground=self.tc,relief='flat',command=self.expandwin)
self.expandb.pack(side='right')#最大化
self.titlebar.pack(fill='x')
self.titlebar.bind('' ,self._startmove,add='+')#移动
self.titlebar.bind('' ,self._movewin,add='+')
可以看出,工具栏已经具备了关闭和放大的按钮以及标题,同时标题栏还拥有拖动功能。
但是,在完成余下的工作的同时,先要让窗口显示出来。
def show(self,x,y,width,height):#显示窗口
self.wd=width
self.hi=height
self.oralx=x
self.oraly=y
self.place(x=x,y=y,width=width,height=height)
那么接下来我们将完成余下的功能。
def destroy(self):#销毁窗口
self.place_forget()
既然可以最大化窗口当然也要恢复窗口大小。
def expandwin(self):#最大化窗口
#记录窗口的起始位置
self.oralx=self.winfo_x()
self.oraly=self.winfo_y()
self.root.update()
w=self.root.winfo_width()
h=self.root.winfo_height()
self.place(x=0,y=0,width=w,height=h)
self.expandb['text']='◪'
self.expandb['command']=self.backexpandwin
self.lockwin()#最大化不能移动
def backexpandwin(self):#恢复窗口大小
self.expandb['text']='□'
self.expandb['command']=self.expandwin
self.place(x=self.oralx,y=self.oraly,width=self.wd,height=self.hi)
self.activewin()
def _startmove(self,event):#记录开始移动的坐标
self.startx=event.x
self.starty=event.y
def _movewin(self,event):#移动窗口
self.place(x=self.winfo_x()+(event.x-self.startx),y=self.winfo_y()+(event.y-self.starty))
这里的额外功能主要是针对子窗口的特殊功能和尽可能模仿主窗口的功能,可以丰富组件的使用。这里给出示例,可以自己拓展。
def lockwin(self):#禁止窗口移动
self.titlebar.unbind('' )
def activewin(self):#允许窗口移动
self.titlebar.bind('' ,self._movewin,add='+')
def noexpand(self):#是否支持放大
self.expandb.pack_forget()
def haveexpand(self):#支持放大
self.expandb.pack()
class ChildFrame(Frame):
'''
这是一个建立在Frame之上的子窗口控件
该子窗口可以嵌入tkinter父窗口,但建议是在窗口而不是在控件中
子窗口可以移动也可以不移动,通过属性设定来改变子窗口的状态
需要注意的是,在内嵌子窗口导入控件时,注意起始高度为32
因为组件限制,ChildFrame只能够实现真正窗口的一小部分功能
'''
def __init__(self,root,title_color,title='title',color='#f0f0f0'):
self.root=root
super().__init__(root,bg=color)#底层
self.title=title
self.tc=title_color
self.titlebar=Frame(self,bg=self.tc)#标题栏
Label(self.titlebar,text=self.title,bg=self.tc,fg='white').place(x=5,y=5)
self.conbar=Frame(self.titlebar,bg=self.tc)
self.conbar.pack(side='right')#工具栏
self.desb=tkButton(self.conbar,text='×',font=('宋体',15),bg=self.tc,fg='white',activeforeground='white',activebackground='red',relief='flat',command=self.destroy)
self.desb.pack(side='right')#关闭按钮
self.desb.bind('' ,lambda event:self.desb.configure(background='red'))
self.desb.bind('' ,lambda event:self.desb.configure(background=self.tc))#当鼠标划过时有红色样式
self.expandb=tkButton(self.conbar,text='□',font=('宋体',15),fg='white',bg=self.tc,activeforeground='white',activebackground=self.tc,relief='flat',command=self.expandwin)
self.expandb.pack(side='right')#最大化
self.titlebar.pack(fill='x')
self.titlebar.bind('' ,self._startmove,add='+')#移动
self.titlebar.bind('' ,self._movewin,add='+')
def show(self,x,y,width,height):#显示窗口
self.wd=width
self.hi=height
self.oralx=x
self.oraly=y
self.place(x=x,y=y,width=width,height=height)
def destroy(self):#销毁窗口
self.place_forget()
def _startmove(self,event):#记录开始移动的坐标
self.startx=event.x
self.starty=event.y
def _movewin(self,event):#移动窗口
self.place(x=self.winfo_x()+(event.x-self.startx),y=self.winfo_y()+(event.y-self.starty))
def lockwin(self):#禁止窗口移动
self.titlebar.unbind('' )
def activewin(self):#允许窗口移动
self.titlebar.bind('' ,self._movewin,add='+')
def backexpandwin(self):#恢复窗口大小
self.expandb['text']='□'
self.expandb['command']=self.expandwin
self.place(x=self.oralx,y=self.oraly,width=self.wd,height=self.hi)
self.activewin()
def expandwin(self):#最大化窗口
#记录窗口的起始位置
self.oralx=self.winfo_x()
self.oraly=self.winfo_y()
self.root.update()
w=self.root.winfo_width()
h=self.root.winfo_height()
self.place(x=0,y=0,width=w,height=h)
self.expandb['text']='◪'
self.expandb['command']=self.backexpandwin
self.lockwin()#最大化不能移动
def noexpand(self):#是否支持放大
self.expandb.pack_forget()
def haveexpand(self):#支持放大
self.expandb.pack()
Tin知识库
tkinter的组件具有很强的拓展性和兼容性,通过二次封装可以实现很多丰富GUI使用的效果。
☀tkinter创新☀