Python GUI项目实战(四)实现学生明细窗体GUI的设计
ccwgpt 2024-10-24 09:05 37 浏览 0 评论
前言
在上一节Python GUI项目实战(三)实现信息查询功能 我们实现了在主窗体中通过单条件查询或者组合查询进行学生信息的筛选功能,系统能够在所有的数据中精确地找到某个具体的符合条件的学生信息。但是我们发现在主窗体中显示的都是概要信息,如果我们想要鼠标双击表格中的某一项就想查看某个学生的详细信息该怎么实现呢?
这一节我们将搭建一个显示学生详细信息的明细窗体,显示该学生的所有信息,只要双击表格中的某一行就能打开。同时显示学生明细信息时我们的明细窗体要表现出三种不同的状态,同时应对显示、添加、和修改三种情况。在不同的状态下窗体显示的得标题是不同的。我们现在就开始着手操作吧这个项目吧~
一、学生明细窗体GUI基本布局
我们新建一个detailgui.py文件,显示学生明细信息。主要显示的内容有:学号、姓名、性别、出生日期、身份证号码、手机号码、邮箱地址、家庭住址、入学时间、专业、紧急联系人、紧急联系电话;其中性别我们通过Radiobutton的方式显示,其余都通过Label和Entry来显示。
本文重点讲解的内容是逻辑与实现部分;关于tkinter布局的基础知识,这里主要用到的主要是Label标签和Entry输入框还有Radiobutton单选框的绘制,我们前面的文章Python基础学习笔记(十三)图形化界面Tkinter 已经做了具体的讲解,这里就不再继续重复介绍了。
下面直接给出界面布局的代码:
from tkinter import *
from tkinter.ttk import *
import os
class DetailWindow(Tk):
def __init__(self):
super().__init__()
self.title("学生明细信息")
self.geometry("600x500+600+150")
self.resizable(0,0) # 不能改变大小
# 加载控件
self.setup_UI()
def setup_UI(self):
# 设置style
self.Style01 = Style()
self.Style01.configure("title.TLabel",font=("微软雅黑",25,"bold"),foreground = "navy")
self.Style01.configure("TLabel", font=("微软雅黑", 16, "bold"), foreground="navy")
self.Style01.configure("TButton",font=("微软雅黑",16,"bold"),foreground = "navy")
self.Style01.configure("TEntry", font=("微软雅黑", 16, "bold"),width = 10)
self.Style01.configure("TRadiobutton",font=("微软雅黑",16,"bold"),foreground = "navy")
# 加载上面的banner
self.Login_image = PhotoImage(file = "."+os.sep+"img"+os.sep+"stu_detail_banner.png")
self.Label_image = Label(self,image = self.Login_image)
self.Label_image.pack()
# 添加一个title
self.var_title = StringVar()
self.Label_title = Label(self,text="==明细窗体==",style = "title.TLabel")
self.Label_title.place(x=380,y=20)
# 加载一个pane
self.Pane_detail = PanedWindow(width = 590,height = 380)
self.Pane_detail.place(x = 5,y = 88)
# 添加属性
# 第一排:学号
self.Label_sno = Label(self.Pane_detail,text = "学号:")
self.Label_sno.place(x=30,y=10)
self.var_sno = StringVar()
self.Entry_sno = Entry(self.Pane_detail,textvariable = self.var_sno,font=("微软雅黑", 16, "bold"),width = 10)
self.Entry_sno.place(x=80,y=8)
# 姓名
self.Label_name = Label(self.Pane_detail,text = "姓名:")
self.Label_name.place(x=220,y=10)
self.var_name = StringVar()
self.Entry_name = Entry(self.Pane_detail,textvariable = self.var_name,font=("微软雅黑", 16, "bold"),width = 10)
self.Entry_name.place(x=270,y=8)
# 性别
self.Label_gender = Label(self.Pane_detail,text = "性别:").place(x=410,y = 10)
self.var_gender = IntVar()
self.Radio_man = Radiobutton(self.Pane_detail,text="男",variable = self.var_gender,value = 1)
self.Radio_man.place(x=460,y = 10)
self.Radio_woman = Radiobutton(self.Pane_detail, text="女", variable=self.var_gender, value=0)
self.Radio_woman.place(x=510, y=10)
# 第二排:出生日期
self.Label_age = Label(self.Pane_detail,text="出生日期:")
self.Label_age.place(x=30,y=60)
self.var_age = StringVar()
self.Entry_age = Entry(self.Pane_detail,textvariable = self.var_age,font=("微软雅黑", 16, "bold"),width = 12)
self.Entry_age.place(x=110,y=58)
# 身份证号码
self.Label_id = Label(self.Pane_detail, text="身份证号码:")
self.Label_id.place(x=250, y=60)
self.var_id = StringVar()
self.Entry_id = Entry(self.Pane_detail, textvariable=self.var_id,font=("微软雅黑", 16, "bold"), width=19)
self.Entry_id.place(x=350, y=58)
# 第三排:手机号码
self.Label_mobile = Label(self.Pane_detail, text="手机号码:")
self.Label_mobile.place(x=30, y=110)
self.var_mobile = StringVar()
self.Entry_mobile = Entry(self.Pane_detail, textvariable=self.var_mobile,font=("微软雅黑", 16, "bold"), width=14)
self.Entry_mobile.place(x=110, y=108)
# 邮箱地址
self.Label_email = Label(self.Pane_detail, text="邮箱地址:")
self.Label_email.place(x=270, y=110)
self.var_email = StringVar()
self.Entry_email = Entry(self.Pane_detail, textvariable=self.var_email,font=("微软雅黑", 16, "bold"), width=19)
self.Entry_email.place(x=350, y=108)
# 第四排:家庭住址
self.Label_home = Label(self.Pane_detail, text="家庭住址:")
self.Label_home.place(x=30, y=160)
self.var_address = StringVar()
self.Entry_home = Entry(self.Pane_detail, textvariable=self.var_address,font=("微软雅黑", 16, "bold"), width=43)
self.Entry_home.place(x=110, y=158)
# 第五排:入学时间
self.Label_studyin = Label(self.Pane_detail, text="入学时间:")
self.Label_studyin.place(x=30, y=210)
self.var_studyin = StringVar()
self.Entry_studyin = Entry(self.Pane_detail, textvariable=self.var_studyin,font=("微软雅黑", 16, "bold"), width=12)
self.Entry_studyin.place(x=110, y=208)
# 专业:
self.Label_pro = Label(self.Pane_detail, text="专业:")
self.Label_pro.place(x=250, y=210)
self.var_pro = StringVar()
self.Entry_pro = Entry(self.Pane_detail, textvariable=self.var_pro,font=("微软雅黑", 16, "bold"), width=24)
self.Entry_pro.place(x=300, y=208)
# 第六排:紧急联系人
self.Label_emcon = Label(self.Pane_detail, text="紧急联系人:")
self.Label_emcon.place(x=30, y=260)
self.var_emcon = StringVar()
self.Entry_emcon = Entry(self.Pane_detail, textvariable=self.var_emcon,font=("微软雅黑", 16, "bold"), width=11)
self.Entry_emcon.place(x=120, y=258)
# 紧急联系电话
self.Label_emtel = Label(self.Pane_detail, text="紧急联系人电话:")
self.Label_emtel.place(x=250, y=260)
self.var_emtel = StringVar()
self.Entry_emtel = Entry(self.Pane_detail, textvariable=self.var_emtel,font=("微软雅黑", 16, "bold"), width=16)
self.Entry_emtel.place(x=380, y=258)
# 放置两个按钮
self.Button_save = Button(self,text = "保存",style = "TButton").place(x=400,y=472)
self.Button_exit = Button(self,text = "关闭",style = "TButton").place(x=502,y=472)
if __name__ == '__main__':
this_window = DetailWindow()
this_window.mainloop()
效果演示:
二、加载明细窗体
加载学生明细信息我们应该设置三种状态:查看、添加、修改;
1. 功能需求
- 在查看状态下,标题是:查看学生明细,各信息栏输入框中所有的信息都是只读状态,并且右下角的保存按钮处于隐藏状态;
- 在添加状态下,标题是:添加学生明细,各信息栏输入框清空,右下角保存按钮可用;
- 在修改状态下,标题是:修改学生明细,各信息栏除学号不能修改外,其余信息栏均可修改,并且右下角保存按钮可用。
2. 触发条件
我们实现查看学生明细信息的三种状态的触发条件:
3. 遇到问题
为了能查看学生明细信息,我们要在主窗体中定义一个函数load_detail_window(),在此之前我们要导入detailgui模块,调用DetailWindow类;
import detailgui
def load_detail_window(self):
detail_window = detailgui.DetailWindow()
接着,我们再定义一个add_student的函数,在这个函数中调用load_detail_window方法
def add_student(self):
self.load_detail_window()
然后在按钮中添加command参数,其值为add_student; 这样做似乎貌似实现了简单的加载学生明细窗体的功能,实际上当我们执行程序,点击添加学生按钮后,系统会报错
_tkinter.TclError: image "pyimage4" doesn't exist
这是什么原因呢?
在tkinter里面有一个类Tk,其功能是产生一个主窗体,我们前面每次创建窗体时都用到了它。但是在tkinter里有一个规定,应用程序同时只能运行一个主窗体。而这里我们的主窗体一直在运行,是没有办法再加载一个主窗体(明细信息)的。如果想同时加载两个窗体,第二个窗体必须要以子窗体的形式打开,这里我们就可以使用Toplevel来创建子窗体。
所以,detialgui的DetailWindow类所继承的类应该由Tk,换成Toplevel即可。 这时候又出现了一个小bug,pane与明细窗体发生了脱离,这是因为我们前面创建pane容器的时候忘记设置它的属主了,这里添加一个构建函数中添加一个self参数就可以了。现在点击添加学生按钮,就可以正常加载明细信息窗口了!
所以,出现这个问题的根源所在就是:使用Tk这个类实例化一个窗体,这个窗体是一个主窗体。已经实例化了一个主窗体,再实例化一个是不可以的。所以第二个窗体必须用Toplevel实例化。
三、实现三种状态加载明细窗体
1. 点击按钮触发
前面我们已经实现了添加明细信息的功能,现在我们继续实现修改明细信息的功能。我们新定义一个update_student()函数:
def update_student(self):
self.load_detail_window()
然后在修改学生按钮中添加command参数即可。
2. 双击表格触发
我们想双击TreeView中的某一行表格,就能触发查看明细信息的功能,首先我们定义一个查看明细信息的方法view_student(),由于双击是一个事件,所以在调用函数的时候需要添加一个参数event
def view_student(self,event):
self.load_detail_window()
然后在 setup_UI()函数的结尾处,添加触发双击表格某一行的事件,写法是:使用bind()方法,第一个参数一定要以Double开头,体现是一个双击事件,第二个函数为对应的触发函数。
self.Tree.bind("<Double-1>",self.view_student)
效果演示:
四、呈现三种不同的状态
以上三种触发函数实现的都是同一种功能,然而我们想实现查看、添加、修改三种不同状态,那么怎样才能体现差异化呢?
1.添加标志参数
在实例化明细窗体的时候,添加一个标志参数action_flag,我们通过区分action_flag参数的值,来确定以什么样的模式进行加载。 这里我们规定:
- 当action_flag = 1时,表示查看模式;
- 当action_flag = 2时,表示添加模式;
- 当action_flag = 3时,表示修改模式。
2. 修改窗体标题
我们在明细窗体的构造函数中,定义一个全局变量:
self.flag = action_flag
再定义一个修改窗体标题的函数:
def load_windows_flag(self):
if self.flag == 1:
self.Label_title.configure(text="==查看学生明细==")
elif self.flag == 2:
self.Label_title.configure(text="==新建学生明细==")
elif self.flag == 3:
self.Label_title.configure(text="==修改学生明细==")
创建好修改标题的函数后,不要忘了在构造函数中添加上:
self.load_windows_flag()
我们在主窗体函数中也定义一个全局变量,作为修改明细窗体标题的标志位:
self.action_flag = 0
然后在主窗体函数中,给load_detail_window()函数添加参数self.action_flag:
def load_detail_window(self):
detail_window = detailgui.DetailWindow(self.action_flag)
与此同时,add_student()、update_student()、view_student()三个方法也要做相应的修改:
def add_student(self):
self.action_flag = 2
self.load_detail_window()
def update_student(self):
self.action_flag = 3
self.load_detail_window()
def view_student(self,event):
self.action_flag = 1
self.load_detail_window()
这样三种不同的触发事件,对应的明细窗体标题也发生了相应的变化:
点击添加学生按钮,明细窗体标题显示“添加学生明细”;点击修改学生按钮,明细窗体标题显示“修改学生明细”;双击表格学生学生信息某一行,明细窗体标题显示“查看学生明细”。
最后
本节我们完成了明细窗体GUI的搭建,设置了明细窗体的查看模式、添加模式、和修改模式,并且实现了在不同触发按钮下同一个明细窗体显示不同的标题。希望小伙伴们不仅仅学习的同时,思考一下为什么要这么做?我们是怎么实现呈现三种不同窗体状态的,并且结合着前面的文章自己动手练一练,所有的数据源、素材和源码直接私信我,我发给你。
本节的明细窗体GUI的搭建已经完成了,前期准备工作已经做好了,下一节我们就要正式将数据源学生信息填充进明细窗体中显示出来,敬请期待吧~
小伙伴们觉得文章内容还不错的话,点赞、转发、关注安排一下^_^,感谢您的支持~
相关推荐
- 十分钟让你学会LNMP架构负载均衡(impala负载均衡)
-
业务架构、应用架构、数据架构和技术架构一、几个基本概念1、pv值pv值(pageviews):页面的浏览量概念:一个网站的所有页面,在一天内,被浏览的总次数。(大型网站通常是上千万的级别)2、u...
- AGV仓储机器人调度系统架构(agv物流机器人)
-
系统架构层次划分采用分层模块化设计,分为以下五层:1.1用户接口层功能:提供人机交互界面(Web/桌面端),支持任务下发、实时监控、数据可视化和报警管理。模块:任务管理面板:接收订单(如拣货、...
- 远程热部署在美团的落地实践(远程热点是什么意思)
-
Sonic是美团内部研发设计的一款用于热部署的IDEA插件,本文其实现原理及落地的一些技术细节。在阅读本文之前,建议大家先熟悉一下Spring源码、SpringMVC源码、SpringBoot...
- springboot搭建xxl-job(分布式任务调度系统)
-
一、部署xxl-job服务端下载xxl-job源码:https://gitee.com/xuxueli0323/xxl-job二、导入项目、创建xxl_job数据库、修改配置文件为自己的数据库三、启动...
- 大模型:使用vLLM和Ray分布式部署推理应用
-
一、vLLM:面向大模型的高效推理框架1.核心特点专为推理优化:专注于大模型(如GPT-3、LLaMA)的高吞吐量、低延迟推理。关键技术:PagedAttention:类似操作系统内存分页管理,将K...
- 国产开源之光【分布式工作流调度系统】:DolphinScheduler
-
DolphinScheduler是一个开源的分布式工作流调度系统,旨在帮助用户以可靠、高效和可扩展的方式管理和调度大规模的数据处理工作流。它支持以图形化方式定义和管理工作流,提供了丰富的调度功能和监控...
- 简单可靠高效的分布式任务队列系统
-
#记录我的2024#大家好,又见面了,我是GitHub精选君!背景介绍在系统访问量逐渐增大,高并发、分布式系统成为了企业技术架构升级的必由之路。在这样的背景下,异步任务队列扮演着至关重要的角色,...
- 虚拟服务器之间如何分布式运行?(虚拟服务器部署)
-
在云计算和虚拟化技术快速发展的今天,传统“单机单任务”的服务器架构早已难以满足现代业务对高并发、高可用、弹性伸缩和容错容灾的严苛要求。分布式系统应运而生,并成为支撑各类互联网平台、企业信息系统和A...
- 一文掌握 XXL-Job 的 6 大核心组件
-
XXL-Job是一个分布式任务调度平台,其核心组件主要包括以下部分,各组件相互协作实现高效的任务调度与管理:1.调度注册中心(RegistryCenter)作用:负责管理调度器(Schedule...
- 京东大佬问我,SpringBoot中如何做延迟队列?单机与分布式如何做?
-
京东大佬问我,SpringBoot中如何做延迟队列?单机如何做?分布式如何做呢?并给出案例与代码分析。嗯,用户问的是在SpringBoot中如何实现延迟队列,单机和分布式环境下分别怎么做。这个问题其实...
- 企业级项目组件选型(一)分布式任务调度平台
-
官网地址:https://www.xuxueli.com/xxl-job/能力介绍架构图安全性为提升系统安全性,调度中心和执行器进行安全性校验,双方AccessToken匹配才允许通讯;调度中心和执...
- python多进程的分布式任务调度应用场景及示例
-
多进程的分布式任务调度可以应用于以下场景:分布式爬虫:importmultiprocessingimportrequestsdefcrawl(url):response=re...
- SpringBoot整合ElasticJob实现分布式任务调度
-
介绍ElasticJob是面向互联网生态和海量任务的分布式调度解决方案,由两个相互独立的子项目ElasticJob-Lite和ElasticJob-Cloud组成。它通过弹性调度、资源管控、...
- 分布式可视化 DAG 任务调度系统 Taier 的整体流程分析
-
Taier作为袋鼠云的开源项目之一,是一个分布式可视化的DAG任务调度系统。旨在降低ETL开发成本,提高大数据平台稳定性,让大数据开发人员可以在Taier直接进行业务逻辑的开发,而不用关...
- SpringBoot任务调度:@Scheduled与TaskExecutor全面解析
-
一、任务调度基础概念1.1什么是任务调度任务调度是指按照预定的时间计划或特定条件自动执行任务的过程。在现代应用开发中,任务调度扮演着至关重要的角色,它使得开发者能够自动化处理周期性任务、定时任务和异...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- MVC框架 (46)
- spring框架 (46)
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- laravel框架 (46)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- JAVA集合框架 (47)
- grpc框架 (55)
- ppt框架 (48)
- 内联框架 (52)
- winform框架 (46)
- gui框架 (44)
- cad怎么画框架 (58)
- ps怎么画框架 (47)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)
- oracle提交事务 (47)