引言
说起对话框,它在程序应用界面中扮演着一个举足轻重的角色,通过对话框,可以更好地与使用者进行交互或者是信息提示,同时还能够减少应用界面本身的位置占用,在界面开发中很有用处。
但是要面对一个显示问题,有时需要对话框频繁弹出,以此来处理各种交互任务。可对于使用者而言,一会一个对话框弹出来,打扰对电脑的正常使用,是很影响对一个应用的感受的,这会使使用效果大大降低。
那么怎么解决这个问题,就需要用到内嵌对话框,使对话框显示在应用窗口中。
tkinter的对话框
自带对话框
众所周知,在tkinter中,输入框在simpledialog
中,当使用这个输入对话框后,会弹出一个输入窗口。如果使用得多了,就会频繁弹出这种输入窗口,让人难免有些厌倦。那么现在,我们开始以输入对话框为例子,开始研究内嵌对话框。
构思
布局
和tkinter自带的输入对话框一样,我们的对话框也需要一个输入框(Entry)接受输入内容,然后通过按钮(Button)返回输入内容。
结构
此外,内嵌输入框还要做到一个功能——如果过对话框没有关闭,程序不能继续执行。也就是说,当对话框出现时,程序不能够再自己运行,要获得输入内容后才能够继续运行。
相信很多人(特别是刚入手tkinter的)看到这就很为难。因为,目前没有任何资料详细说明tkinter的对话框是怎么做到的,除非自己去研究simpledialog
的源码。不过,我现在告诉大家,tkinter根本没有原生对话框(文件对话框除外),我们看到的simpledialog
都是当年的Python开发大神们码出来的(此处应怀有感激心)。在这篇文章,我不打算详细分析simpledialog
的源码,因为我也没有完全看懂。但是我们可以依据其中的基本思路,创造出新的输入对话框。
解决方案
为了完成tkinter的内嵌输入对话框,我们需要用到一个重要函数:wait_window(window)。这个函数存在于每一个tkinter窗口和组件。而且,tkinter中的输入框就是以这个为基础构建的。
这个函数的作用:暂停界面程序,直到被指定的组件被销毁或者是删除。
不要因为这个函数的字面意思而误解其参数的含义。window不只是tkinter窗口(toplevel/tk),也可以是组件(widget)。
创造内嵌输入框
界面布局
这个很随意,因为只是例子:
root=Tk()
#...省略主窗口布局代码
def askstring(master,text):
#主体框架
frame=tk.Frame(master,bg='black',cursor='arrow',highlightthickness=3)
#文本提示/说明
label=tk.Label(frame,bg='black',fg='white',text=text)
label.pack(side='top',fill='x',pady=10)
#输入框
entry=tk.Entry(frame,bg='white',fg='black',font=self['font'],relief='flat')
entry.insert(0,word)
entry.pack(side='top',fill='x',pady=10)
#确认按钮
button=ttk.Button(frame,text='确认')
button.pack(side='top',fill='x')
#内嵌输入对话框
frame.place(x=0,y=0,width=self.winfo_width())
#暂停程序
master.wait_window(frame)
def test():
a=askstring(root)
print(a)
root.after(1000,test)
root.mainloop()
返回输入内容
因为我们使用了wait_window
使界面暂停,所有当按钮被单击,或者是在输入框按下回车时,我们将输入的结果作为主窗口的一个属性,然后再删除内嵌输入框,返回这个值:
def askstring(master,text):
#...
#输入框
entry=tk.Entry(frame,bg='white',fg='black',font=self['font'],relief='flat')
entry.insert(0,word)
entry.bind('<Return>',lambda event:over_askstring(master,frame,entry))
entry.pack(side='top',fill='x',pady=10)
#确认按钮
button=ttk.Button(frame,text='确认',command=lambda:over_askstring(master,frame,entry))
button.pack(side='top',fill='x')
#内嵌输入对话框
#...
return master.askstring_result
def over_askstring(master,frame,entry):
master.askstring_result=entry.get()
frame.destroy()
完整代码例子
root=Tk()
#...省略主窗口布局代码
def askstring(master,text):
#主体框架
frame=tk.Frame(master,bg='black',cursor='arrow',highlightthickness=3)
#文本提示/说明
label=tk.Label(frame,bg='black',fg='white',text=text)
label.pack(side='top',fill='x',pady=10)
#输入框
entry=tk.Entry(frame,bg='white',fg='black',font=self['font'],relief='flat')
entry.insert(0,word)
entry.bind('<Return>',lambda event:over_askstring(master,frame,entry))
entry.pack(side='top',fill='x',pady=10)
#确认按钮
button=ttk.Button(frame,text='确认',command=lambda:over_askstring(master,frame,entry))
button.pack(side='top',fill='x')
#内嵌输入对话框
frame.place(x=0,y=0,width=self.winfo_width())
#暂停程序
master.wait_window(frame)
return master.askstring_result
def over_askstring(master,frame,entry):
master.askstring_result=entry.get()
frame.destroy()
def test():
a=askstring(root)
print(a)
root.after(1000,test)
root.mainloop()
在TinEngine中的效果
初版
使用TinUI绘制
结语
这是在tkinter中的一个小创意,其界面布局在这篇文章中只是简单说明一下,还可以继续优化。本篇文章只提供思路。
☀tkinter创新☀