Python GUI 编程 01 : Tkinter基础控件

2022-04-30科技306

有时候,做个小项目,没有太多复杂的需求,直接使用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: 鼠标离开部件范围

相关文章

等腰三角形的所有公式?

等腰三角形面积公式 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...

已知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²...

魔兽秘籍是什么?

  greedisgood =黄金木材各加500单位 KeyserSoze =加黄金 LeafItToMe =加木材 PointBreak =加人口上限 whosyourdaddy =无敌且拥有一击必杀 iseedeadpeople =显示全部地图 allyourbasearebelongtous...

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...

请高手帮我把这个大智慧指标 改成选股公式

  黄色区域出现‘S’为选股条件,只需以下函数即可: v0:=VOL*(O C H L)/4; A:=EMA(v0,21)/EMA(VOL,21); SY:=A=ref(A,1); var1:=CLOSEREF(CLOSE,1) AND CLOSEREF(CLOSE,2); Var2:=REF(Va...

已知复数Z 若z

用复数的三角形式求解是可以的,因为这个问题比较简单,用代数形式求解并不困难。 有一个重要的概念,复数是没有大小的,所以由z^2+2z+1/zy=0或x=-1/2 及xx-yy+3xx=1或x=-1,其中x=1不满足⑵,舍去,∴x=-1, 由x=-1/2==y=(√3)/2,y=-(√3)/2,都满足...

侠盗飞车圣安地列斯怎么用秘?

  任何场景直接打应英文 全秘籍: 主要: HESOYAM = 加命、护甲、250000元 【用】 BAGUVIX = 敌 CVWKXAM = 限气 LXGIWYL = 般武器 【用】 KJKSZP...

1光年=( )米=( )千米

The distance light can travel in one year,which is9 500 000 000 000 kilometers. 这句话的意思是:1光年,是9 500 000 000 000公里。 所以,1光年=(95000000亿)米=(95000亿)千米 1光年=约...

魔兽争霸 的密码

  首先按回车键,然后输入你想要的秘籍,秘籍如下: greedisgood =黄金木材各加500单位(如果在后面加空格在加数字的话就加相应数量的黄金木材)比如greedisgood 5000,就是加5000钱和木,(如果在后面加空格在负号再加数字的话就减相应数量的黄金木材)比如greedisgood...

一升和一立方米怎么换算?

在线科普啊! 升在国际单位制中表示为L,其次级单位为毫升(mL)。升与其他容积单位的换算关系为: 1L=1000mL=0.001立方米=1立方分米=1000立方厘米 1L=1dm*1dm*1dm=10cm*10cm*10cm 1mL=1立方厘米=1cc 1立方米= 1000升 升:容积单位。民间有一...