当前位置: 首页 > news >正文

Python GUI编程

前置学习

Tkinter(即 tk interface) 是 Python 标准 GUI 库,无须另行安装,支持跨平台运行。Tkinter 对于 GUI 初学者是十分友好的,学习请参考Tkinter教程(非常详细)。
本文会使用 Tkinter 做两个简单的 GUI 示例。

随机点名系统

源码:

fromtkinterimport*fromtkinterimportmessageboximporttkinter.filedialogimportpickle,os,random,csvclassAttendanceSystem:def__init__(self,root):self.root=root self.root.title("随机点名系统")self.root.geometry("800x600")self.pkl_path="data.pkl"self.file_path=Noneself.students=[]self.is_calling=Falseself.selected=StringVar()defpreload(self):ifnotos.path.exists(self.pkl_path):messagebox.showwarning("警告","未找到pkl文件")returnwithopen(self.pkl_path,'rb')asf:iffile_path:=pickle.load(f):self.file_path=file_pathdefcreate_menu(self):main_menu=Menu(self.root)main_menu.add_cascade(label="文件选择",command=self.open_file)self.root.config(menu=main_menu)defcreate_widgets(self):call_button=Button(self.root,text="开始点名",command=self.start_call,height=3,width=20,bg="skyblue",font=("微软雅黑",16))call_button.place(relx=0.25,rely=0.2,anchor=CENTER)pause_button=Button(self.root,text="停止点名",command=self.pause_call,height=3,width=20,bg="skyblue",font=("微软雅黑",16))pause_button.place(relx=0.75,rely=0.2,anchor=CENTER)dynamic_label=Label(self.root,textvariable=self.selected,font=("微软雅黑",60))dynamic_label.place(relx=0.5,rely=0.5,anchor=CENTER)self.selected.set("None")defstart_call(self):self.load_csv()ifnotself.students:messagebox.showerror("错误","数据加载失败")returnself.is_calling=Trueself.random_caller()defpause_call(self):self.is_calling=Falsedefrandom_caller(self):ifnotself.is_calling:returnself.selected.set(random.choice(self.students))self.root.after(100,self.random_caller)defrun(self):self.preload()self.create_menu()self.create_widgets()self.root.mainloop()defopen_file(self):file_path=tkinter.filedialog.askopenfilename(title="选择CSV文件",filetypes=[("CSV files","*.csv"),("All files","*.*")])ifnotfile_path:returnifnotfile_path.endswith('.csv'):messagebox.showerror("错误","仅支持CSV文件格式")returnself.file_path=file_pathwithopen(self.pkl_path,'wb')asf:pickle.dump(file_path,f)defload_csv(self):ifnotself.file_path:messagebox.showwarning("警告","未选择文件")returnself.students.clear()seen_serials=set()try:withopen(self.file_path,'r',encoding='utf-8')asf:reader=csv.reader(f)rows=list(reader)rows=rows[1:]# 固定从第二行开始读取forrowinrows:serial=int(row[0])name=row[1].strip()ifserialinseen_serials:messagebox.showwarning("警告",f"重复序号:{serial}")continueself.students.append((serial,name))seen_serials.add(serial)exceptExceptionase:self.students.clear()messagebox.showerror("错误",f"读取文件失败:{str(e)}")if__name__=="__main__":root=Tk()system=AttendanceSystem(root)system.run()

CSV 文件格式:

序号,姓名 1,John 2,Mary 3,Robert 4,Jennifer 5,Michael

效果图:

图片预览器

源码:

importtkinterastkfromtkinterimportfiledialog,messagebox,ttkfromPILimportImage,ImageTkfromdatetimeimportdatetimeimportio,os,base64,pickleclassImageViewer:def__init__(self,root):self.root=root self.root.title("图片预览器")self.root.geometry("800x600")self.pkl_path="data.pkl"self.image_list=[]self.current_index=0defpreload(self):ifnotos.path.exists(self.pkl_path):messagebox.showwarning("警告","未找到pkl文件")returntry:withopen(self.pkl_path,"rb")asf:encoded_images=pickle.load(f)self.image_list=[base64.b64decode(img)forimginencoded_images]self.show_image(self.current_index)exceptExceptionase:self.image_list.clear()messagebox.showerror("错误",f"无法加载图片:{e}")defcreate_widgets(self):self.main_frame=ttk.Frame(self.root)self.main_frame.pack(fill=tk.BOTH,expand=True)self.canvas=tk.Canvas(self.main_frame,bg="gray")self.canvas.pack(fill=tk.BOTH,expand=True,padx=10,pady=10)self.canvas.update_idletasks()self.control_frame=ttk.Frame(self.root)self.control_frame.pack(fill=tk.X,padx=10,pady=5)self.btn_upload=ttk.Button(self.control_frame,text="上传图片",command=self.upload_image)self.btn_upload.pack(side=tk.LEFT,padx=5)self.btn_download=ttk.Button(self.control_frame,text="下载图片",command=self.download_image)self.btn_download.pack(side=tk.LEFT,padx=5)self.btn_delete=ttk.Button(self.control_frame,text="删除图片",command=self.delete_image)self.btn_delete.pack(side=tk.LEFT,padx=5)self.btn_save=ttk.Button(self.control_frame,text="保存图片",command=self.save_image)self.btn_save.pack(side=tk.LEFT,padx=5)self.btn_prev=ttk.Button(self.control_frame,text="上一张",command=self.prev_image)self.btn_prev.pack(side=tk.RIGHT,padx=5)self.btn_next=ttk.Button(self.control_frame,text="下一张",command=self.next_image)self.btn_next.pack(side=tk.RIGHT,padx=5)self.status_label=ttk.Label(self.control_frame,text="图片: 0/0")self.status_label.pack(side=tk.RIGHT,padx=5)defupload_image(self):file_path=filedialog.askopenfilename(title="选择图片",filetypes=[("图片文件","*.png *.jpg *.jpeg *.gif *.bmp"),("所有文件","*.*")])ifnotfile_path:returntry:withopen(file_path,"rb")asf:image_data=f.read()self.image_list.append(image_data)self.show_image(len(self.image_list)-1)exceptExceptionase:messagebox.showerror("错误",f"无法打开图片:{e}")defdownload_image(self):ifnotself.image_list:messagebox.showwarning("警告","没有图片可下载")returntry:filename=datetime.now().strftime("%Y%m%d%H%M%S")+".png"withopen(filename,"wb")asf:f.write(self.image_list[self.current_index])messagebox.showinfo("成功","图片已下载")exceptExceptionase:messagebox.showerror("错误",f"无法下载图片:{e}")defdelete_image(self):ifnotself.image_list:messagebox.showwarning("警告","没有图片可删除")returntry:self.image_list.pop(self.current_index)ifself.current_index>=len(self.image_list)-1:self.current_index-=1self.show_image(self.current_index)messagebox.showinfo("成功","图片已删除")exceptExceptionase:messagebox.showerror("错误",f"无法删除图片:{ee}")defsave_image(self):ifnotself.image_list:messagebox.showwarning("警告","没有图片可保存")returntry:encoded_images=[base64.b64encode(img).decode('utf-8')forimginself.image_list]withopen(self.pkl_path,"wb")asf:pickle.dump(encoded_images,f)messagebox.showinfo("成功","图片已保存")exceptExceptionase:messagebox.showerror("错误",f"无法保存图片:{e}")defshow_image(self,index):ifnotself.image_listorindex<0orindex>=len(self.image_list):messagebox.showerror("错误","图片索引超出范围")returnself.current_index=index image_data=self.image_list[index]try:image=Image.open(io.BytesIO(image_data))img_width,img_height=image.size canvas_width=self.canvas.winfo_width()canvas_height=self.canvas.winfo_height()ifcanvas_height==1andcanvas_width==1:self.canvas.image=ImageTk.PhotoImage(image)self.canvas.create_image(0,0,anchor=tk.NW,image=self.canvas.image)self.status_label.config(text=f"图片:{index+1}/{len(self.image_list)}")returnscale=min(canvas_width/img_width,canvas_height/img_height)new_width=int(img_width*scale)new_height=int(img_height*scale)image=image.resize((new_width,new_height),Image.Resampling.LANCZOS)self.canvas.image=ImageTk.PhotoImage(image)self.canvas.delete("all")x=(canvas_width-image.width)//2y=(canvas_height-image.height)//2self.canvas.create_image(x,y,anchor=tk.NW,image=self.canvas.image)self.status_label.config(text=f"图片:{index+1}/{len(self.image_list)}")exceptExceptionase:messagebox.showerror("错误",f"无法显示图片:{e}")defprev_image(self):if(n:=len(self.image_list))>0:new_index=self.current_index-1ifself.current_index>0elsen-1self.show_image(new_index)defnext_image(self):if(n:=len(self.image_list))>0:new_index=self.current_index+1ifself.current_index<n-1else0self.show_image(new_index)defrun(self):self.create_widgets()self.preload()self.root.mainloop()if__name__=="__main__":root=tk.Tk()app=ImageViewer(root)app.run()

效果图:

http://www.jsqmd.com/news/748754/

相关文章:

  • PresentBench:PPT自动化评估系统的技术解析与应用
  • [MediaForge] 架构之美:依赖倒置原则与好莱坞法则在微内核中的实战
  • 批量导入缺字段问题解决方案
  • 【深度学习新浪潮】AI蛋白质结构预测2026最新研究进展
  • 审核到底是什么?别再把它当“检查“了
  • cc-openclaw-bridge:轻量级数据桥接与协议转换中间件实战指南
  • 不止于改游戏:挖掘Cheat Engine在Windows调试与逆向分析中的隐藏用法
  • 思源宋体终极应用指南:7种字重如何为你的项目注入专业灵魂
  • 【Backend Flow工程实践 26】Hierarchical Design Flow:为什么大芯片后端必须分层、抽象、合并和签核?
  • ARM RealView Debugger代码搜索与替换技术详解
  • 基于伪标签自训练的YOLOv10无监督域适应:从入门到彻底搞懂
  • 一句话,AI 文档变专业印刷品
  • 【Backend Flow工程实践 27】Backend Script Template:一个可维护的后端脚本体系应该如何组织?
  • 遗产自动分配程序,颠覆遗产争夺纠纷,遗嘱上链,条件触发自动执行,不可篡改。
  • MySQLWorkbench初学者使用教程
  • 如何用waifu2x-caffe实现专业级图像放大:3步快速上手指南
  • 构建AI编程助手洞察系统:从数据采集到代码质量分析
  • ESP32 MQTT传输图片翻车记:手把手教你调大缓冲区,解决大数据发送失败问题
  • 2026年5月AI编程工具横评:Cursor 3 vs TRAE SOLO vs Claude Code,谁才是真正的生产力革命?
  • 改进YOLOv10:引入课程学习的渐进式难例挖掘策略,让目标检测更智能!
  • 【Backend Flow工程实践 28】Backend Flow Engineering 总结:从脚本、日志、报告到工程闭环
  • Mnesis:构建本地AI知识库,实现智能语义检索与关联
  • AI寻根:用姓氏追溯商朝身份,打造趣味历史探索工具
  • Simulink MPC模块实战:手把手教你替换电机电流环PI控制器(附避坑指南)
  • Chrome的AI开发天团:3500万行代码的团队,居然这么玩AI写代码
  • Nuvoton M091系列MCU:工业传感应用的理想选择
  • Sublime text3配置C/C++编译环境
  • 一篇文章带你了解CSDN旗下有多少CSDN相关的域名
  • 8b/10b编码原理及其在高速串行通信中的应用
  • Android自动化抓取框架androidclaw:轻量级数据采集与自动化测试实践