引言
这里指的类ppt是指组件主体由图片选择框,原始图片显示框组成,木有自己的编辑功能。
框架
类似PPT,左边是多个图片缩略图的选择框,右边大半部分是原始图片的显示区域。因为原始图片可能会超过显示框,所以显示框必须配备横向和纵向两个滚动条。
那么通过构思得到的组件框架如下:
class ImageView(LabelFrame):
"""一个可以查看多个图片的组件,看起来像ppt"""
def __init__(self,master,**kw):
LabelFrame.__init__(self,master,**kw)
self.imgtext=scrolledtext.ScrolledText(self,state='disabled',cursor='arrow')#缩小照片显示区
self.imgtext.place(relx=0,rely=0,relwidth=0.21,relheight=1)
self.imgtext.vbar['width']=10
self.imgframe=Frame(self,bg='white',relief='flat')
self.imgback=Text(self.imgframe,bg='white',relief='flat',cursor='arrow',state='disabled')#正常照片显示区
self.vbar=Scrollbar(self.imgframe,orient='vertical',width=9)
self.vbar.pack(side='right',fill='y')
self.vbar.config(command=self.imgback.yview)
self.hbar=Scrollbar(self.imgframe,orient='horizontal',width=9)
self.hbar.pack(side='bottom',fill='x')
self.hbar.config(command=self.imgback.xview)
self.imgback.pack(side='right',fill='both',expand=True)
self.imgback.config(xscrollcommand=self.hbar.set, yscrollcommand=self.vbar.set)
self.imgframe.place(relx=0.21,rely=0,relwidth=0.79,relheight=1)
self.images={}#存放缩略图与原图信息
在 scrolledtext.ScrolledText 中,可以直接更改滚动条颜色。在这里没有使用颜色参数。
添加图片
为了使组件加载时不用耗费过多时间,设立了专门的函数加入图片并进行显示操作。在添加图片的函数中,图片路径将被作为参数使用。
添加图片分为三个步骤。第一步,先对图片进行尺寸处理,使其能够完整显示在选择框内;第二步,生成与缩略图对应的图片信息,在稍后使用;第三步,显示缩略图,绑定单击信息。
当鼠标经过选项框的图片时,label最好还能够显示橙色(选定颜色)。
方便起见,该组件不对gif进行特殊处理。
#添加图片与生成相对应的图片信息
def append_image(self,img:str):
path=img
img=Image.open(img)
width,height=img.size
self.update()
w=self.imgtext.winfo_width()
h=w*2//3
eimg=ImageTk.PhotoImage(img)
img.thumbnail((w,h),Image.ANTIALIAS)
eimgtk=ImageTk.PhotoImage(img)
#键:小图片,值:大图片
self.images[eimgtk]=eimg
self._append_imagelabel(eimgtk,path)#显示图片
#显示图片并绑定
def _append_imagelabel(self,eimgtk,path):
#:eimgtk 经过ImageTk.Photoimage处理后的文件。同时是在字典中的缩小图片,键
#通过label添加图片,让其能够绑定事件
path=re.findall('.*\\\\(.*)',path)[0]
self.imgtext['state']='normal'
imglabel=Label(self.imgtext,relief='groove',image=eimgtk,text=path,compound='bottom')
imglabel.bind('<Enter>',lambda event:imglabel.config(bg='#EED546'))#显示提醒与离开
imglabel.bind('<Leave>',lambda event:imglabel.config(bg='#f0f0f0'))
imglabel.bind('<Button-1>',lambda event:self.change_img(event,eimgtk))
self.imgtext.window_create('end',window=imglabel)
self.imgtext.insert('end','\n\n')
self.imgtext.update()
self.imgtext['state']='disabled'
显示图片
在图片label被单击后,在原图显示框中显示被选中缩略图的原图
def change_img(self,event,eimgtk):#来自 _append_imagelabel 的单击绑定
#:eimgtk 缩略图
self.imgback['state']='normal'
self.imgback.delete(1.0,'end')
self.imgback.image_create('end',image=self.images[eimgtk])
self.imgback['state']='disabled'
完整代码
class ImageView(LabelFrame):
"""一个可以查看多个图片的组件,看起来像ppt"""
def __init__(self,master,**kw):
LabelFrame.__init__(self,master,**kw)
self.imgtext=scrolledtext.ScrolledText(self,state='disabled',cursor='arrow')#缩小照片显示区
self.imgtext.place(relx=0,rely=0,relwidth=0.21,relheight=1)
self.imgtext.vbar['width']=10
self.imgframe=Frame(self,bg='white',relief='flat')
self.imgback=Text(self.imgframe,bg='white',relief='flat',cursor='arrow',state='disabled')#正常照片显示区
self.vbar=Scrollbar(self.imgframe,orient='vertical',width=9)
self.vbar.pack(side='right',fill='y')
self.vbar.config(command=self.imgback.yview)
self.hbar=Scrollbar(self.imgframe,orient='horizontal',width=9)
self.hbar.pack(side='bottom',fill='x')
self.hbar.config(command=self.imgback.xview)
self.imgback.pack(side='right',fill='both',expand=True)
self.imgback.config(xscrollcommand=self.hbar.set, yscrollcommand=self.vbar.set)
self.imgframe.place(relx=0.21,rely=0,relwidth=0.79,relheight=1)
self.images={}#存放缩略图与原图信息
def change_img(self,event,eimgtk):
#:eimgtk 缩略图
self.imgback['state']='normal'
self.imgback.delete(1.0,'end')
self.imgback.image_create('end',image=self.images[eimgtk])
self.imgback['state']='disabled'
def _append_imagelabel(self,eimgtk,path):
#:eimgtk 经过ImageTk.Photoimage处理后的文件。同时是在字典中的缩小图片,键
#通过label添加图片,让其能够绑定事件
path=re.findall('.*\\\\(.*)',path)[0]
self.imgtext['state']='normal'
imglabel=Label(self.imgtext,relief='groove',image=eimgtk,text=path,compound='bottom')
imglabel.bind('<Enter>',lambda event:imglabel.config(bg='#EED546'))#显示提醒与离开
imglabel.bind('<Leave>',lambda event:imglabel.config(bg='#f0f0f0'))
imglabel.bind('<Button-1>',lambda event:self.change_img(event,eimgtk))
self.imgtext.window_create('end',window=imglabel)
self.imgtext.insert('end','\n\n')
self.imgtext.update()
self.imgtext['state']='disabled'
def append_image(self,img:str):
path=img
img=Image.open(img)
width,height=img.size
self.update()
w=self.imgtext.winfo_width()
h=w*2//3
eimg=ImageTk.PhotoImage(img)
img.thumbnail((w,h),Image.ANTIALIAS)
eimgtk=ImageTk.PhotoImage(img)
#键:小图片,值:大图片
self.images[eimgtk]=eimg
self._append_imagelabel(eimgtk,path)
效果
结语
虽然tkinter提供的原始组件比较少,但是通过组合和添加新的功能函数,同样可以让GUI界面变得丰富。
☀tkinter创新☀