Python GUI 编程 01 : Tkinter基础控件

2022-04-30科技260

有时候,做个小项目,没有太多复杂的需求,直接使用Python自带的GUI包Tkinter是个不错的选择,本文参考了使用过程的一些理解,给大伙做些分享。

一个小case:长度转换import tkinter as tkfrom tkinter import ttkfrom tkinter.messagebox import showerror,showinfo,showwarningdef calculate(*args): try: value=float(feet.get) meters.set(float(0.3048*value*10000.0+0.5)/10000.0) except ValueError: passroot=tk.Tkroot.title('Feet to Meters')mainframe=ttk.Frame(root,padding='3 3 12 12',) # 设置留白距离mainframe.grid(row=0,column=0,sticky=(tk.N,tk.W,tk.E,tk.S))root.columnconfigure(0,weight=1) # 列自动延展root.rowconfigure(0,weight=1) # 行自动延展feet=tk.StringVarfeet_entry=ttk.Entry(master=mainframe,width=7,textvariable=feet)feet_entry.grid(row=1,column=2,sticky='we')meters=tk.StringVarttk.Label(mainframe,textvariable=meters).grid(row=2,column=2,sticky='we')ttk.Button(mainframe,text='Calculate',command=calculate).grid(row=3,column=3,sticky='w')ttk.Label(mainframe,text='feet').grid(column=3,row=1,sticky='w')ttk.Label(mainframe,text='is equivalent to').grid(column=1,row=2,sticky='e')ttk.Label(mainframe,text='meters').grid(column=3,row=2,sticky='w')for child in mainframe.winfo_children: # 迭代各子控件 child.grid_configure(padx=5,pady=5) # 配置widgets边距feet_entry.focus # 设置焦点控件root.bind('Return',calculate) # 根窗体绑定键盘回车事件root.mainloop面向对象的方法import tkinter as tkfrom tkinter import ttkclass FeetToMeters: def __init__(self, master): master.title('Feet to Meters') mainframe = ttk.Frame(master, padding='3 3 12 12') mainframe.grid(column=0, row=0, sticky='news') master.columnconfigure(0, weight=1) master.rowconfigure(0, weight=1) self.feet = tk.StringVar feet_entry = ttk.Entry(mainframe, width=7, textvariable=self.feet) feet_entry.grid(column=2, row=1, sticky='we') self.meters = tk.StringVar ttk.Label(mainframe, textvariable=self.meters).grid(column=2, row=2, sticky='we') ttk.Button(mainframe, text='Calculate', command=self.calculate).grid(column=3, \ row=3, sticky='w') ttk.Label(mainframe, text='feet').grid(column=3, row=1, sticky='w') ttk.Label(mainframe, text='is equivalent to').grid(column=1, row=2, sticky='e') ttk.Label(mainframe, text='meters').grid(column=3, row=2, sticky='w') for child in mainframe.winfo_children: child.grid_configure(padx=5, pady=5) feet_entry.focus master.bind('Return', self.calculate) def calculate(self, *args): try: self.value = float(self.feet.get) self.meters.set(int(0.3048*self.value*10000.0+0.5)/10000.0) except ValueError: passroot=tk.TkFeetToMeters(root)root.mainloop 基本窗体部件import tkinter as tkfrom tkinter import ttkroot = tk.Tkroot.resizable(width=False,height=True) # 主窗体尺寸是否可调#! Framef=ttk.Frame(root)f.configure( padding=(2,2), # 元组定义的留白方向:lrtb/(lr,tb)/(l,t,r,b) width=500, height=180, borderwidth=5, ) f['relief'] = 'sunken' # 浮雕样式f.pack(fill = 'both')#! Labellbl = ttk.Label(f, text='starting...\nthe second line', padding=20, justify='right', anchor=tk.CENTER)lbl.grid(row=0)lbl.bind('Enter', lambda event: lbl.configure(text='Move mouse insede'))lbl.bind('Leave', lambda e: lbl.configure(text='Move mouse outside'))lbl.bind('ButtonPress-1', lambda e: lbl.configure(text=f'Clicked left mouse button at {e.x}, {e.y}'))lbl.bind('3', lambda e: lbl.configure(text='Clicked right mouse button'))lbl.bind('Double-1', lambda e: lbl.configure(text='Double clicked'))lbl.bind('B3-Motion',lambda e: lbl.configure(text=f'rigth button dragto {e.x},{e.y}'))# #! Buttonbtn = ttk.Button(f, text='OK', default='active', command=lambda: lbl.configure(text='Redo again'))btn.grid(row=1, sticky=tk.SE)#// btn.configure(state='disabled') # 设置状态为禁用#// print(btn.instate(['!disabled'])) # 判断当前状态#! CheckButtonmeasureSystem1 = tk.StringVarchbtn1=ttk.Checkbutton(f, text='Use Metric', variable=measureSystem1, onvalue='metric', offvalue='imperial', command=lambda: print(measureSystem1.get) )chbtn1.grid(row=2, sticky=tk.SW)measureSystem2 = tk.StringVarchbtn2=ttk.Checkbutton(f, text='Use Metric', variable=measureSystem2, onvalue='metric', offvalue='imperial', command=lambda: print(measureSystem2.get) )chbtn2.grid(row=2, column=1, sticky=tk.SW)chbtn2.configure(state='disabled')print(chbtn2.instate(['alternate'])) # 状态是否可选root.bind('Return', lambda event: btn.invoke) # 调用btn#! RidioButtongender = tk.StringVar(value='Male')rad_btn1 = ttk.Radiobutton(f, text='Male', variable=gender, value='Male',\ command=lambda:print(gender.get))rad_btn2 = ttk.Radiobutton(f, text='Female', variable=gender, value='Female',\ command=lambda:print(gender.get))rad_btn3 = ttk.Radiobutton(f, text='Unsure', variable=gender, value='Unsure',\ command=lambda:print(gender.get))rad_btn1.grid(row=3, column=0, sticky=tk.W)rad_btn2.grid(row=3, column=1, sticky=tk.W)rad_btn3.grid(row=3, column=2, sticky=tk.E)#! Entryimport redef check_num(newval): valid = re.match('^[0-9a-z]*$', newval) is not None and len(newval) = 5 if not valid: showerror(title='提示', message='错误的输入') num.set(contents.get) return valid# 传递调用对象输入框内的最新值(%P)check_num_wrapper=(root.register(check_num), '%P')contents = tk.StringVarentry = ttk.Entry(f, textvariable=contents, validate='all', # 指定触发校验的事件 # 调用根窗体注册的事件方法 validatecommand=check_num_wrapper )entry.grid(row=4, sticky='se')#// entry.bind('Enter', lambda e: contents.set('')) # 重置输入框#// root.bind('ButtonPress-3', lambda e: entry.delete(0, 'end')) # 删除指定内容num = tk.StringVare = ttk.Entry(f, textvariable=num, state='disabled')e.grid(column=1, row=4, sticky='we')root.bind('ButtonPress-3', lambda e: entry.insert(0,'new content')) # 初始化输入框#// def it_has_been_written(*args):#// print('entry has been writting...')#// contents.trace_add('write', it_has_been_written)#//entry.configure(state='readonly')root.mainloop词条的输入有效性验证import tkinter as tkfrom tkinter import ttkimport reroot = tk.Tkv = tk.StringVardef test(P, i , s , V, w, v, S, d): valid = re.match('^china$', P) is not None if valid: print('correct') print(P, i , s , V, w, v, S, d) return True else: print('wrong ' \ 'entering') print(P, i , s , V, w, v, S, d) return Falsetest_wrapper = root.register(test) # 封装函数到根窗体e1=ttk.Entry( root, textvariable=v, validate='focus', # 调用根窗体注册的事件函数,并将对象的调用参数传递给事件函数 validatecommand=(test_wrapper, '%P', '%i', '%s', '%V', '%W', '%v', '%S', '%d') )e1.insert(0, "china")e2 = tk.Entry(root, textvariable=v)e1.pack(padx=5, pady=5, fill=tk.X)e2.pack(padx=5, pady=5, ill=tk.X)root.mainloop百分号占位符的意义:

'%P'--当输入框可编辑时,值为输入框的最新文本内容;

'%i'--用户插入或删除操作的位置索引,获失焦点或textvariable变量值被修改该值为-1;

'%s'--调用验证函数前输入框的文本内容;

'%V'--调用验证函数的原因;

'%W'--当前组件名;

'%v'--当前validate选项的值;

'%S'--当插入和删除操作触发验证时,表示文本被插入和删除的内容;

'%d'--操作代码0删除/1插入/2获失焦点或textvariable变量值被修改;

Case: 加法计算器import tkinter as tkfrom tkinter import ttkroot = tk.Tkframe = ttk.Frame(root) # 把整个布局放到框架中,更好调节frame.pack(padx=10, pady=10)v1 = tk.StringVarv2 = tk.StringVarv3 = tk.StringVardef validate(content): if content.isdigit: # isdigit方法,这是str的一个函数,只允许输入数字 return True else: print("invalid inputing") return False# 注册根窗体事件方法testCmd = root.register(validate) # 通过register方法转换为validatecommand选项能接收的函数ttk.Entry(frame, textvariable=v1, width=10, validate='key', \ validatecommand=(testCmd, '%P')).grid(row=0, column=0) # 用%P获取最新输入的字符串ttk.Label(frame, text='+').grid(row=0, column=1)ttk.Entry(frame, textvariable=v2, width=10, validate='key', \ validatecommand=(testCmd, '%P')).grid(row=0, column=2)ttk.Label(frame, text='=').grid(row=0, column=3)ttk.Entry(frame, textvariable=v3, width=10, state='readonly', validate='key', \ validatecommand=(testCmd, '%P')).grid(row=0, column=4)def calc: result = int(v1.get) + int(v2.get) v3.set(result)ttk.Button(frame, text='计算结果', command=calc).grid(row=1, column=2, pady=5)root.mainloopCase:邮编格式验证import tkinter as tkfrom tkinter import ttkimport re root = tk.Tkerrmsg = tk.StringVarformatmsg = "Zip should be ##### or #####-####"def check_zip(newval, op): errmsg.set('') valid = re.match('^[0-9]{5}(\-[0-9]{4})?$', newval) is not None btn.state(['!disabled'] if valid else ['disabled']) if op == 'key': # 当validate='key'时 ok_so_far = re.match('^[0-9\-]*$', newval) is not None and len(newval) = 10 if not ok_so_far: errmsg.set(formatmsg) return ok_so_far elif op == 'focusout': if not valid: errmsg.set(formatmsg) return validcheck_zip_wrapper = (root.register(check_zip), '%P', '%V') # validatecommand对象必须是元组或列表zip = tk.StringVarf = ttk.Frame(root)f.grid(column=0, row=0)ttk.Label(f, text='Name:').grid(column=0, row=0, padx=5, pady=5)ttk.Entry(f).grid(column=1, row=0, padx=5, pady=5)ttk.Label(f, text='Zip:').grid(column=0, row=1, padx=5, pady=5)e=ttk.Entry(f, textvariable=zip, validate='all', validatecommand=check_zip_wrapper, \ invalidcommand=lambda: e.focus)e.grid(column=1, row=1, padx=5, pady=5)btn=ttk.Button(f, text='Process')btn.grid(column=2, row=1, padx=5, pady=5)btn.state(['disabled'])msg=ttk.Label(f, foreground='red', textvariable=errmsg, anchor='center')msg.grid(column=0, row=2, padx=5, columnspan=3, pady=5)root.mainloop下拉列表框:Comboboximport tkinter as tkfrom tkinter import ttkfrom faker import Fakerroot = tk.Tkf = ttk.Frame(root)f.grid(column=0, row=0, sticky='news')countryVar = tk.StringVarcountry = ttk.Combobox(f, textvariable=countryVar, height=10,) # height 可见高度10行def getCountrys(n): f = Faker for _ in range(n): yield str(_+1) + " " + f.countrycountry.configure(values = list(getCountrys(15)))country.state(['readonly']) # 列表框状态为只读country.bind('ComboboxSelected',lambda e: print(f'{countryVar.get} select ...')) # 绑定虚拟事件country.current(5) # combobox.current(index) 通过设置索引值选定取值country.pack(fill=tk.X)#! 样式管理器ttk.styles = ttk.Styles.configure('Danger.TFrame', background='red', borderwidth=5, relief='raised')ttk.Frame(root, width=250, height=200, style='Danger.TFrame').gridroot.mainloop 事件处理:Event HandlingActivate: 窗体被激活Deactivate: 窗体被切换或未被激活MouseWheel: 鼠标滚轮动作KeyPress: 键盘按键被按下KeyRelease: 键盘按键释放ButtonPress: 鼠标按键按下ButtonRelease: 鼠标按键释放Motion: 鼠标运动Configure: 窗体部件大小或位置发生变化Destroy: 部件被销毁FocusIn: 部件获得键盘输入焦点FocusOut: 部件失去键盘输入焦点Enter: 鼠标进入部件范围Leave: 鼠标离开部件范围

相关文章

求出下边竖式中A,T,V,S各代表什么数字?

a=0;t=1;v=3;s=8这个是用逻辑分析得来的.个位数字,两个数相加等于其中的一个数,其中之一只能是0,从所给条件看,只有A有是0的可能.所以A=0;万位数字:两个一位数字相加最多只能向前进1,当然也可能由后位相加再进1的,所以万位可能是1或2,也就是T有可能是1或2,如果是2的话,那么V最大...

等腰三角形的所有公式?

等腰三角形面积公式 s=(1/2)*底*高 s=(1/2)*a*b*sinC (C为a,b的夹角) s=1/2的周长*内切圆半径 s=(1/2)*底*高 s=(1/2)*a*b*sinC c=a+b+c s=1/2ah(底*高/2) s=1/2absinC(两边与夹角正弦乘积的一半) s=1/2ac...

对联广告JS代码怎么写呢?

  html xmlns=。   xue51。com)/title/headbody leftmargin=0 topmargin=0script type=text/javascriptvar delta=0。115 var collection; function floaters { thi...

求值2013分之1加2013分之2加2013分之3

因为1 2012=2 2011=3 2010=...=1006 1007, 所以1 2 3 ... 2012=1006×(1 2012)=1006×2013, 所以原式=2013分之(1006×2013)=1006. 分母相同,分子相加,所以分母是2013,分子是1 2 …… 2012,首尾相加都等...

(1/2 1/3 …1/1997) (1 1/2 … 1/1996-(1 1/2… 1/1997)……怎么解

(1/2 1/3 …… 1/1997)*(1 1/2 …… 1/1996)-(1 1/2 ...... 1/1997)*(1/2 1/3 ...... 1/1996)=(1/2 1/3 …… 1/1997)*(1/2 …… 1/1996)-(1/2 ...... 1/1997)*(1/2 1/3 ....

(2 4 6 . 1998)=?

原式=1+(3-2)+(5-4)+(7-6)+......+(1999-1998) =1+1+1+1+......+1,共计1000个1. =1*1000 =1000 或者原式=1000*(1+1999)/2-999*(2+1998)/2 =1000*1000-999*1000 =1000(1000...

已知a=2011²+2011²×2012²+2012²?

a=2011²+2001²×2012²+2012²=2011²+2011²×2012²+(2011+1)²=2011²+2011²×2012²+2011²+2×2011+1=2011²×2012²+2×2011²+2×2011+1=2011²×2012²+2×2011²+2×2011+1=2011²...

163cm换算成几英尺几英寸是多少?

1英寸=2.54cm 1英尺=30.48cm 1英尺=12英寸 163cm是多少英尺: 163÷30.48≈5.3478(英尺) 即:163cm约是5.3478英尺。 163cm是多少英寸: 163÷2.54≈64.1732(英寸) 即:163cm约是64,1732英寸。 163cm是多少英尺多少英...

1公分是多少厘米?

1公分=1厘米 扩展资料度:即长度,和人民生活密切相关,原始人布指为寸,布掌为尺,舒肘为丈,到了秦始皇统一度量衡,直至如今的现代计量技术的出现,古代度制演变反映着历史的变迁。 ①夏 1尺=10寸(1尺=24.9厘米) ②商 1尺=10寸,1寸=10分(1尺=31.1厘米) ③周 1丈=10尺,1尺=...

幂指函数的对数求导法则问题

【1】所谓【对数求导法则】是按如下步骤求y=f(x)的导数: ①取绝对值|y|=|f(x)|, ②取对数ln|y|=ln|f(x)|, ③求导y'/y=[ln|f(x)|]', ④得到y'=y*[ln|f(x)|]'=f(x)*[ln|f(x)|]'. 所以根本没有任何问题。 以上过程教材都讲得很清...

英制:英尺,英寸与公制的换算?

长度单位换算:1千米(公里)=2市里0.6241英里=0.540海里 1米=3市尺=3.281英尺 1海里=1.852千米(公里)=3.704市里=1.150英里 1市尺=0.333米=1.094英尺 1英里=1.609千米(公里)=3.219市里 1英尺=12英寸=0.914市尺 面积单位换算:1...

魔兽密码

   在游戏中按下回车,输入以下密码后再按下回车即可:   iseedeadpeople 地图全开   allyourbasearebelongtous 立即获胜   somebodysetupusthebomb 立即失败   thereisnospoon 无限魔法   whosyourdad...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。