tkinter绘制组件(43)——对话框
- 引言
- 布局
- 窗口
- 初始化
- 对话框类型
- 弹窗显示和窗口冻结
- 内容返回
- 信息提示
- 输入对话框
- 函数封装
- 效果
- 测试代码
- 最终效果
- github项目
- pip下载
- 结语
引言
严格来说,对话框是控件的组合,不是一个控件,但是是一种常见的功能交互界面,因此,TinUI有必要实现内置的对话框。
TinUI的对话框基于TinUIDialog类,该类设计和tkinter内置Dialog一样,不作为外部调用类,而是通过内置的showinfo
等函数封装,让开发者直接使用这些函数。TinUI对话框分为信息提示框和输入框,都将通过TinUIDialog类实现。
布局
窗口
弹窗窗口就是一个简单的Toplevel,但是绑定了父窗口,或者说产生该对话框的窗口。
class Dialog(Toplevel):
"""
TinUI对话框基础类
"""
def __init__(self,master,dialogtype='normal',**options):
super().__init__(master,**options)
self.withdraw()
self.tinui=BasicTinUI(self)
self.tinui.pack(fill='both',expand=True)
self.type=dialogtype#对话框类型
self.resizable(False,False)
self.tk.call('wm', 'iconbitmap', self._w, '-default', '')
这里设置wm_iconbitmap用了tk命令,是为了关闭窗口图标。
下面,我们将以消息提示框为例,简要说明TinUIDialog的实现。
初始化
TinUIdialog的封装函数会调用对话框基础类,通过给定参数进行窗口初始化。
def initial_msg(self,title,content,yestext='OK',notext='Cancel'):
"""
初始化对话框-消息类
"""
YES=yestext
NO=notext
self.title(title)
self.protocol('WM_DELETE_WINDOW',lambda:self.return_msg(None))
这里用
initial_msg
命名是因为这是信息提示对话框,输入对话框的初始化方法命名为initial_input
。
对话框类型
这里的类型指的是对话框的内容性质,比如普通信息、重要信息、警告、错误、问询等等。
输入问答框有文本、整数、浮点数输入等等。
在窗口初始化时,直接通过判断窗口类型进行基础配置。
if self.type=='normal':
pass
elif self.type=='info':
self.tinui['bg']='#ffffff'
icon_uid=self.tinui.add_paragraph((5,5),text='\uE946',fg='#5969e0',font='{Segoe Fluent Icons} 14',anchor='w')
self.tinui.addtag_withtag('content',icon_uid)
elif self.type=='success':
self.tinui['bg']='#dff6dd'
icon_uid=self.tinui.add_paragraph((5,5),text='\uE73E',fg='#0f7b0f',font='{Segoe Fluent Icons} 14',anchor='w')
self.tinui.addtag_withtag('content',icon_uid)
elif self.type=='warning':
self.tinui['bg']='#fff4ce'
icon_uid=self.tinui.add_paragraph((5,5),text='\uE7BA',fg='#9d5d00',font='{Segoe Fluent Icons} 14',anchor='w')
self.tinui.addtag_withtag('content',icon_uid)
elif self.type=='error':
self.tinui['bg']='#fde7e9'
icon_uid=self.tinui.add_paragraph((5,5),text='\uEA39',fg='#c42b1c',font='{Segoe Fluent Icons} 14',anchor='w')
self.tinui.addtag_withtag('content',icon_uid)
elif self.type=='question':
self.tinui['bg']='#ffffff'
icon_uid1=self.tinui.add_paragraph((5,5),text='\uEA3A',fg='#5969e0',font='{Segoe Fluent Icons} 14',anchor='w')
icon_uid2=self.tinui.add_paragraph((5,5),text='\uF142',fg='#5969e0',font='{Segoe Fluent Icons} 14',anchor='w')
self.tinui.addtag_withtag('content',icon_uid1)
self.tinui.addtag_withtag('content',icon_uid2)
这是目前TinUIdialog支持的对话框类型样式
接下来是初始化文本信息和按钮组。这部分内容比BasicTinUI单独绘制一个控件简单多了,直接给代码。
content_uid=self.tinui.add_paragraph((35,5),text=content,anchor='w')
self.tinui.addtag_withtag('content',content_uid)
content_bbox=self.tinui.bbox('content')
btn_width=(content_bbox[2]-content_bbox[0])/2
button_width=btn_width-10 if btn_width>110 else 100
button_endy=self._endy()+15
yesbutton_uid=self.tinui.add_button2(((content_bbox[0]+content_bbox[2])/2-5,button_endy),text=YES,minwidth=button_width,command=lambda e:self.return_msg(True),anchor='ne')[-1]
nobutton_uid=self.tinui.add_button2(((content_bbox[0]+content_bbox[2])/2+5,button_endy),text=NO,minwidth=button_width,command=lambda e:self.return_msg(False),anchor='nw')[-1]
self.tinui.add_back((),(yesbutton_uid,nobutton_uid),bg='#f3f3f3',fg='#f3f3f3',linew=9)
需要注意,我们希望按钮组平铺满整个底部,所以才有关于布局长度和位置的计算,也就是第2~6行在做的计算。
弹窗显示和窗口冻结
既然是弹窗,就要有弹窗的样子。该功能由TinUIDialog.load_window
方法实现
居中显示:
def load_window(self):
#获取窗口内所有控件的bbox,窗口居中布局
bboxall=self.tinui.bbox('all')
w,h=bboxall[2]-bboxall[0],bboxall[3]-bboxall[1]+1
screenw=self.winfo_screenwidth()
screenh=self.winfo_screenheight()
x,y=(screenw-w)/2,(screenh-h)/2
self.geometry(f'{w}x{h}+{int(x)}+{int(y)-10}')
self.deiconify()
self.tinui.config(scrollregion=bboxall)
锁定父窗口、等待弹窗响应、获取全窗口(tcl/tk层面)焦点与响应、等待弹窗消失,这些就是窗口的冻结,等交互内容被确定后,返回内容,同时弹窗销毁,自动释放全窗口(tcl/tk增面)集中响应。
self.transient(self.master)
self.focus_set()
self.wait_visibility()
self.grab_set()
self.wait_window(self)
return self.result
self.result
的确定如下:
def return_msg(self,val):
#返回消息
self.result=val
self.destroy()
self.master.focus_set()
内容返回
限于篇幅,被模块不给出代码。
信息提示
点击“确认按钮”,返回True。
点击“取消按钮”,返回False
关闭窗口,返回None
输入对话框
点击“确认按钮”,如果输入符合规则,返回输入内容,否则继续输入。
点击“取消按钮”、关闭窗口,返回None
函数封装
以show_info
为例:
def show_info(master,title,content):
"""
显示信息对话框
"""
dialog=Dialog(master,'info')
return dialog.initial_msg(title,content)
效果
测试代码
if __name__=='__main__':
root=Tk()
root.iconbitmap('LOGO.ico')
a=show_msg(root,'test','hello world!')
# print(a)
show_info(root,'test','show information\nhello world!')
show_success(root,'test','Success!\nhello world! hello world! hello world! hello world!')
show_warning(root,'test','this is a warning\nhello world!')
show_error(root,'test','something is wrong\nhello world! hello world! hello world! hello world!')
show_question(root,'test','Do you want to continue?')
b=ask_string(root,'test','input something input something input something input something')
ask_integer(root,'test','input integer')
ask_float(root,'test','input float')
# print(b)
root.mainloop()
最终效果
普通信息
重要信息
成功提醒
警告
错误提醒
询问提醒
普通输入、整数输入、浮点输入均为同样模板,但是点击“确认按钮”后的内容处理方法有些许不一样。
github项目
TinUI的github项目地址
pip下载
pip install tinui
结语
通过导入TinUIdialog中的函数,即可直接使用对话框。
from tinui import show_info,show_error,...
TinUI-5.5中,可以通过from tinui import ...
导入TinUI、TinUIDialog中的类和函数。
🔆tkinter创新🔆