Tkinter信息管理系统

1.登录界面

import tkinter as tk
from PIL import Image, ImageTk
from tkinter import messagebox
from tkinter import ttk
from Mainpage import *
from DB import *

class Login:
    '''
    登录界面
    '''
    def __init__(self, master=tk.Tk):
        '''
        初始化登录界面
        :param master: 父窗口
        '''
        self.master = master
        self.master.title("登录")
        self.master.geometry("500x500+650+200") # 设置窗口大小
        self.create_widgets()

    def create_widgets(self):
        '''
        创建登录界面的控件
        '''
        self.label_username = ttk.Label(self.master, text="用户名:")
        self.label_username.pack()
        self.entry_username = ttk.Entry(self.master)
        self.entry_username.pack()

        self.label_password = ttk.Label(self.master, text="密码:")
        self.label_password.pack()
        self.entry_password = ttk.Entry(self.master, show="*")
        self.entry_password.pack()

        self.button_login = ttk.Button(self.master, text="登录", command=self.login)
        self.button_login.pack()

    def login(self):
        '''
         登录按钮的回调函数
         '''
        username = self.entry_username.get()
        password = self.entry_password.get()
        exist_flag,tip = DB().searchPersonByname(username)

        # 登录验证逻辑
        if exist_flag and password == "xu":
            messagebox.showinfo("登录成功", f"欢迎,{tip[0]['name']}!")
            # 在这里添加登录成功后的操作
            self.master.destroy()
            self.open_main_Page(2)
        elif exist_flag == False and password == 'xu':
            messagebox.showerror("登录失败", "用户不存在!")
            self.master.destroy()
            self.open_main_Page(0)

        elif username == "admin" and password == "admin":
            messagebox.showinfo("登录成功", f"欢迎,{username}!")
            self.master.destroy()
            self.open_main_Page(1)

        else:
            messagebox.showerror("登录失败", "用户名或密码错误!")

    def open_main_Page(self, user_flag):
        '''
        打开主界面
        :param user_flag: 用户类型,1为管理员,2为普通用户'''
        if user_flag:
            root = tk.Tk()
            MainPage(root)
            root.mainloop()

if __name__ == "__main__":
    '''
    程序入口
    '''
    root = tk.Tk()
    imgpath = "login_title.gif"
    img = Image.open(imgpath)
    photo = ImageTk.PhotoImage(img)
    canvas = tk.Canvas(root,width=img.width, height=img.height,bd=0, highlightthickness=0)
    canvas.create_image(150,150,image=photo)
    canvas.pack()
    app = Login(root)
    root.mainloop()

其中login_title.gif为登陆界面的头像

2.主界面MainPage

import tkinter as  tk
from Implement import *
from Login import *



class MainPage:
    '''
    主界面
    '''
    def __init__(self,master: tk.Tk):
        '''
        :param master: 父容器
        设定主界面的各项参数,初始化各个子界面
        '''
        self.root = master
        self.root.title("家谱管理系统")
        # self.root.configure(bg="white")
        self.root.geometry('900x600+400+150')
        self.root.iconbitmap('标头.ico')
        self.createPage()

    def createPage(self):
        '''
        创建各个子界面
        AboutPage:关于
        AddPage:添加
        SearchPage:查询
        DeletePage:删除
        ShowPage:显示绘制图表
        UpdatePage:修改
        ImportPage:导入

        '''
        self.aboutpage = AboutPage(self.root)
        self.addpage = AddPage(self.root)
        self.searchpage = SearchPage(self.root)
        self.deletepage = DeletePage(self.root)
        self.showpage = ShowPage(self.root)
        self.updatepage = UpdatePage(self.root)
        self.importpage = ImportPage(self.root)

        topmenu = tk.Menu(self.root)

        topmenu.add_command(label="添加",command=self.showadd,font=("宋体", 15))
        topmenu.add_command(label="查询",command=self.showsearch,font=("宋体", 15))
        topmenu.add_command(label="删除",command=self.showdelete,font=("宋体", 15))
        topmenu.add_command(label="显示",command=self.showshow,font=("宋体", 15))
        topmenu.add_command(label="修改",command=self.showupdate,font=("宋体", 15))
        topmenu.add_command(label="导入", command=self.showimport,font=("宋体", 15))
        topmenu.add_command(label="关于", command=self.showabout,font=("宋体", 15))
        self.root["menu"] = topmenu
        self.aboutpage.pack()

    def showabout(self):
        '''
        显示关于界面
        ,并隐藏其他界面'''
        self.aboutpage.pack()
        self.addpage.pack_forget()
        self.searchpage.pack_forget()
        self.deletepage.pack_forget()
        self.showpage.pack_forget()
        self.updatepage.pack_forget()
        self.importpage.pack_forget()

    def showadd(self):
        '''
        显示添加界面
        ,并隐藏其他界面'''
        self.aboutpage.pack_forget()
        self.addpage.pack()
        self.searchpage.pack_forget()
        self.deletepage.pack_forget()
        self.showpage.pack_forget()
        self.updatepage.pack_forget()
        self.importpage.pack_forget()

    def showsearch(self):
        '''
        显示查询界面
        ,并隐藏其他界面'''
        self.aboutpage.pack_forget()
        self.addpage.pack_forget()
        self.searchpage.pack()
        self.deletepage.pack_forget()
        self.showpage.pack_forget()
        self.updatepage.pack_forget()
        self.importpage.pack_forget()

    def showdelete(self):
        '''
        显示删除界面
        ,并隐藏其他界面'''
        self.aboutpage.pack_forget()
        self.addpage.pack_forget()
        self.searchpage.pack_forget()
        self.deletepage.pack()
        self.showpage.pack_forget()
        self.updatepage.pack_forget()
        self.importpage.pack_forget()

    def showshow(self):
        '''
        显示显示界面
        ,并隐藏其他界面'''
        self.aboutpage.pack_forget()
        self.addpage.pack_forget()
        self.searchpage.pack_forget()
        self.deletepage.pack_forget()
        self.showpage.pack()
        self.updatepage.pack_forget()
        self.importpage.pack_forget()

    def showupdate(self):
        '''
        显示修改界面
        ,并隐藏其他界面'''
        self.aboutpage.pack_forget()
        self.addpage.pack_forget()
        self.searchpage.pack_forget()
        self.deletepage.pack_forget()
        self.showpage.pack_forget()
        self.updatepage.pack()
        self.importpage.pack_forget()

    def showimport(self):
        '''
        显示导入界面
        ,并隐藏其他界面'''
        self.aboutpage.pack_forget()
        self.addpage.pack_forget()
        self.searchpage.pack_forget()
        self.deletepage.pack_forget()
        self.showpage.pack_forget()
        self.updatepage.pack_forget()
        self.importpage.pack()



if __name__ == '__main__':
    root = tk.Tk()
    MainPage(root)
    root.mainloop()

标头代表左上角那个小图标

3.实现方法Implement

主要包含模块各个函数的实现方法,每一个类代表一个模块

有关于,查找,导出,添加,展示,删除,修改等功能

from tkinter import ttk
import tkinter as tk
import DB as DB
from datetime import datetime
from tkinter import messagebox
import time
import Family_Tree as FT





#创建输入界面模板
def createPage(self, elseflag,elsename,function):#elseflag代表可拓展计数,最多三个,function代表拓展功能,elsename代表拓展功能名称
    # 创建页面
    #创建界面样式

    ttk.Style().configure('TLabel', font=('宋体', 12))
    ttk.Style().configure('TButton', font=('宋体', 12))
    ttk.Style().configure('TEntry', font=('宋体', 12))
    ttk.Style().configure('TRadiobutton', font=('宋体', 12))

    ttk.Label(self, text='姓名').grid(row=0, column=0, padx=(0, 10), pady=(10, 0))
    ttk.Entry(self, textvariable=self.name).grid(row=0, column=1, padx=(0, 10), pady=(10, 0))
    ttk.Label(self, text='性别').grid(row=1, column=0, padx=(0, 10), pady=(10, 0))
    ttk.Radiobutton(self, text='男', variable=self.sex, value=0).grid(row=1, column=1, padx=(0, 10), pady=(10, 0))
    ttk.Radiobutton(self, text='女', variable=self.sex, value=1).grid(row=1, column=2, padx=(0, 10), pady=(10, 0))
    ttk.Label(self, text='出生日期').grid(row=2, column=0, padx=(0, 10), pady=(10, 0))
    ttk.Entry(self, textvariable=self.birthday).grid(row=2, column=1, padx=(0, 10), pady=(10, 0))
    ttk.Label(self,textvariable=self.date_status).grid(row=2, column=2, padx=(0, 10), pady=(10, 0))
    ttk.Label(self, text='地址').grid(row=3, column=0, padx=(0, 10), pady=(10, 0))
    ttk.Entry(self, textvariable=self.address).grid(row=3, column=1, padx=(0, 10), pady=(10, 0))
    ttk.Label(self, text='学历').grid(row=4, column=0, padx=(0, 10), pady=(10, 0))
    ttk.Entry(self, textvariable=self.degree).grid(row=4, column=1, padx=(0, 10), pady=(10, 0))
    ttk.Label(self, text='电话').grid(row=5, column=0, padx=(0, 10), pady=(10, 0))
    ttk.Entry(self, textvariable=self.phone).grid(row=5, column=1, padx=(0, 10), pady=(10, 0))
    ttk.Label(self,text='子嗣').grid(row=6, column=0, padx=(0, 10), pady=(10, 0))
    ttk.Entry(self, textvariable=self.child).grid(row=6, column=1, padx=(0, 10), pady=(10, 0))
    #ttk.Button(self, text='添加', command=self.add_Record).grid(row=6, column=0, padx=(0, 10), pady=(10, 0))
    ttk.Button(self, text='清空', command=self.clear_All).grid(row=7, column=1, padx=(0, 10), pady=(10, 0))
    tk.Label(self, textvariable=self.status).grid(row=8, column=1, padx=(0, 10), pady=(10, 0))
    if elseflag>0:
         ttk.Button(self, text=elsename[0], command=function[0]).grid(row=7, column=0, padx=(0, 10), pady=(10, 0))
    if elseflag-1>0:
         ttk.Button(self, text=elsename[1], command=function[1]).grid(row=7, column=2, padx=(0, 10), pady=(10, 0))
    if elseflag-2>0:
         ttk.Button(self, text=elsename[2], command=function[2]).grid(row=7, column=3, padx=(0, 10), pady=(10, 0))

#创建treeview控件模板
def createTreeview(self,treedata_function,extend_num,extend_name,extend_function):   #treedata_function为插入表格数据,extend_num为扩展按钮数量,最多支持四个,extend_name为扩展按钮名称,extend_function为扩展按钮功能
    # 创建表格
    flag,columns = DB.DB().getCsvHead()
    print(columns)
    if flag :
        self.tree = ttk.Treeview(self, columns=columns,show='headings',displaycolumns='#all')
        self.tree.heading('name', text='姓名',anchor='center') # 显示表头
        self.tree.heading('sex', text='性别',anchor='center') # 显示表头
        self.tree.heading('age', text='年龄',anchor='center') # 显示表头
        self.tree.heading('birthday', text='出生日期',anchor='center') # 显示表头
        self.tree.heading('address', text='地址',anchor='center') # 显示表头
        self.tree.heading('degree', text='学历',anchor='center') # 显示表头
        self.tree.heading('phone', text='电话',anchor='center') # 显示表头
        self.tree.heading('child', text='子嗣',anchor='center') # 显示表头
        self.tree.column('name', width=80, anchor='center') # 设置列宽
        self.tree.column('sex', width=40, anchor='center') # 设置列宽
        self.tree.column('age', width=40, anchor='center') # 设置列宽
        self.tree.column('birthday', width=100, anchor='center') # 设置列宽
        self.tree.column('address', width=100, anchor='center') # 设置列宽
        self.tree.column('degree', width=50, anchor='center') # 设置列宽
        self.tree.column('phone', width=100, anchor='center') # 设置列宽
        self.tree.column('child', width=100, anchor='center') # 设置列宽
        self.tree.pack( fill=tk.BOTH, expand=True)
        treedata_function()
            # 拓展功能按钮
        for i in range(extend_num):
            ttk.Button(self,text=extend_name[i],command=extend_function[i]).pack()
        return self.tree
    else:
        print(columns)






    
class AboutPage(tk.Frame):
    def __init__(self,root):
        super().__init__(root)
        tk.Label(self, text='关于作者:由 厘不哩布 制作').pack()

class AddPage(tk.Frame):
    def __init__(self,root):
        super().__init__(root)
        self.name = tk.StringVar(value='')
        self.sex = tk.IntVar()
        self.birthday = tk.StringVar(value='')
        self.address = tk.StringVar(value='')
        self.degree = tk.StringVar(value='')
        self.phone = tk.StringVar(value='')
        self.child = tk.StringVar(value='')  #子嗣
        # 插入状态
        self.status = tk.StringVar()
        #日期状态
        self.date_status = tk.StringVar(value='如2000-1-1')
        elseflag = 1
        elsename = ['添加']
        function = [self.add_Record]
        createPage(self,elseflag,elsename,function)
        print('创建添加页面')
           

    def add_Record(self):
        print('添加记录')
        age = 0
        birthday_one = self.birthday.get()
        true_or_false = True # 日期格式是否正确
                # 设置样式
        style = ttk.Style()
        style.configure('TLabel', font=('宋体', 12))
        style.configure('TButton', font=('宋体', 12))
        style.configure('TEntry', font=('宋体', 12))
        style.configure('TRadiobutton', font=('宋体', 12))
        try:
            # 尝试计算年龄
            age = datetime.now().year - int(birthday_one.split('-')[0])
            # 如果日期格式正确,跳出循环
            true_or_false = True
        except:
            true_or_false = False
            messagebox.askretrycancel('错误', '日期格式错误,请重新输入')
        if self.sex.get() == 0:
                    person_info = {'name': str(self.name.get()),
                       'sex':  '男',
                       'age': str(age),
                       'birthday': str(self.birthday.get()),
                       'address': str(self.address.get()),
                       'degree': str(self.degree.get()),
                       'phone': str(self.phone.get()),
                       'child': str(self.child.get())
                       }
        else:
                    person_info = {'name': str(self.name.get()),
                       'sex':  '女',
                       'age': str(age),
                       'birthday': str(self.birthday.get()),
                       'address': str(self.address.get()),
                       'degree': str(self.degree.get()),
                       'phone': str(self.phone.get()),
                       'child': str(self.child.get())
                       }
        print(person_info)
        # 添加记录#########################################
        if all(value.strip() != "" for value in person_info.values()):    # 判断是否为空,如果为空则提示
            if true_or_false:  # 日期格式正确
                flag,tip = DB.DB().addPerson(person_info)
                 #flag代表true/false,tip代表提示信息
            else:
                flag,tip = False,'日期格式错误,请重新输入'
            if flag:
                DB.Export().exportCsv()
        else:
            flag,tip = False,'请输入完整信息'
            messagebox.askretrycancel('错误', '请输入完整信息')

        # #############################################
        self.status.set(tip)

    def clear_All(self):
        # 清空所有输入框
        self.name.set('')
        self.sex.set('')
        self.birthday.set('')
        self.address.set('')
        self.degree.set('')
        self.phone.set('')
        self.status.set('清空成功,请重新输入')


class SearchPage(tk.Frame):
    def __init__(self,root):
        super().__init__(root)
        style = ttk.Style()
        style.configure('TLabel', font=('宋体', 12))
        style.configure('TButton', font=('宋体', 12))
        self.status = tk.StringVar()
        self.extend_num = 4
        self.extend_name = ['刷新', '按姓名查找', '按性别查找', '按学位查找']
        self.extend_function = [self.refresh, self.search_by_name, self.search_by_sex, self.search_by_degree]
        ttk.Label(self, text='总览', style='TLabel').pack(side=tk.TOP, pady=10)
        self.tree = createTreeview(self,self.show_treedata,self.extend_num,self.extend_name,self.extend_function)
        ttk.Button(self,text='按年龄升序排序',command=self.sort_by_age_up).pack(side=tk.TOP,pady=10)
        ttk.Button(self,text='按年龄降序排序',command=self.sort_by_age_down).pack(side=tk.TOP,pady=10)
        ttk.Label(self, textvariable=self.status, style='TLabel').pack(side=tk.TOP, pady=10)

    def sort_by_age_up(self):# 按年龄排序
        flag,person_dic = DB.DB().searchPersonAll()
        if flag:
             DB.DB().sortPerson_Age(False, person_dic)
        self.refresh()
        self.status.set('按年龄升序排序成功')

    def sort_by_age_down(self):# 按年龄排序
        flag,person_dic = DB.DB().searchPersonAll()
        if flag:
             DB.DB().sortPerson_Age(True, person_dic)
        self.refresh()
        self.status.set('按年龄降序排序成功')

             
    
    def show_treedata(self):
        # 查询所有记录,转化为元组
        flag,person_dic = DB.DB().searchPersonAll()
        if flag:
             for i in person_dic:
                  person_tuple = tuple(i.values())
                  self.tree.insert('', 'end', values=person_tuple)



    def refresh(self):
        # 删除所有记录,保证记录都是最新的
        for _ in map(self.tree.delete, self.tree.get_children()):
             pass
        # 查询所有记录,转化为元组
        flag,person_dic = DB.DB().searchPersonAll()
        if flag:
             for i in person_dic:
                  person_tuple = tuple(i.values())
                  self.tree.insert('', 'end', values=person_tuple)
    def search_name(page_name,name):
         name_f = name.get()
         # 查询所有记录,转化为元组
         for _ in map(page_name.tree.delete, page_name.tree.get_children()):
              pass
         flag,person_dic = DB.DB().searchPersonByname(name_f)
         if flag:
              for i in person_dic:
                   person_tuple = tuple(i.values())
                   page_name.tree.insert('', 'end', values=person_tuple)
         else:
              page_name.tree.insert('', 'end', values='无此记录')

    def search_sex(page_name,sex):
         sex_f = sex.get()
         # 查询所有记录,转化为元组
         for _ in map(page_name.tree.delete, page_name.tree.get_children()):
              pass
         flag,person_dic = DB.DB().searchPersonBysex(sex_f)
         if flag:
              for i in person_dic:
                   person_tuple = tuple(i.values())
                   page_name.tree.insert('', 'end', values=person_tuple)
         else:
              page_name.tree.insert('', 'end', values='无此记录')
    def search_degree(page_name,degree):
         degree_f = degree.get()
         # 查询所有记录,转化为元组
         for _ in map(page_name.tree.delete, page_name.tree.get_children()):
              pass
         flag,person_dic = DB.DB().searchPersonBydegree(degree_f)
         if flag:
              for i in person_dic:
                   person_tuple = tuple(i.values())
                   page_name.tree.insert('', 'end', values=person_tuple)
         else:
                page_name.tree.insert('', 'end', values='无此记录')
    def search_by_name(self):
        style = ttk.Style()
        style.configure('TLabel', font=('宋体', 12))
        style.configure('TButton', font=('宋体', 12))
        extend_num = 0
        extend_name = ['查找']
        extend_function = [lambda:0]
        #page_name = tk.Tk()  # 创建一个新窗口
        page_name = tk.Toplevel()  # 创建一个新窗口
        page_name.title('按姓名查找')
        page_name.geometry('500x500+400+150')  # 设置窗口大小
        name = tk.StringVar()
        #ttk.Label(page_name.root, text='    请输入姓名     ', style='TLabel').grid(row=0, column=2, padx=5, pady=5)
        ttk.Label(page_name, text='姓名:', style='TLabel').pack( padx=5, pady=5)
        ttk.Entry(page_name, textvariable=name, width=30).pack( padx=5, pady=5)
        page_name.tree = createTreeview(page_name,lambda:0,extend_num,extend_name,extend_function)
        ttk.Button(page_name, text='查询', command=lambda:SearchPage.search_name(page_name,name), style='TButton').pack(padx=5, pady=5)
        page_name.mainloop()

    def search_by_sex(self):
        style = ttk.Style()
        style.configure('TLabel', font=('宋体', 12))
        style.configure('TButton', font=('宋体', 12))
        extend_num = 0
        extend_name = ['查找']
        extend_function = [lambda:0]
        #page_name = tk.Tk()  # 创建一个新窗口
        page_name = tk.Toplevel()  # 创建一个新窗口
        page_name.title('按性别查找')
        page_name.geometry('500x500+400+150')  # 设置窗口大小
        sex = tk.StringVar()
        #ttk.Label(page_name.root, text='    请输入姓名     ', style='TLabel').grid(row=0, column=2, padx=5, pady=5)
        ttk.Label(page_name, text='性别:', style='TLabel').pack( padx=5, pady=5)
        ttk.Entry(page_name, textvariable=sex, width=30).pack( padx=5, pady=5)
        page_name.tree = createTreeview(page_name,lambda:0,extend_num,extend_name,extend_function)
        ttk.Button(page_name, text='查询', command=lambda:SearchPage.search_sex(page_name,sex), style='TButton').pack(padx=5, pady=5)
        page_name.mainloop()
    def search_by_degree(self):
        style = ttk.Style()
        style.configure('TLabel', font=('宋体', 12))
        style.configure('TButton', font=('宋体', 12))
        extend_num = 0
        extend_name = ['查找']
        extend_function = [lambda:0]
        #page_name = tk.Tk()  # 创建一个新窗口
        page_name = tk.Toplevel()  # 创建一个新窗口
        page_name.title('按学位查找')
        page_name.geometry('500x500+400+150')  # 设置窗口大小
        degree = tk.StringVar()
        #ttk.Label(page_name.root, text='    请输入姓名     ', style='TLabel').grid(row=0, column=2, padx=5, pady=5)
        ttk.Label(page_name, text='学位:', style='TLabel').pack( padx=5, pady=5)
        ttk.Entry(page_name, textvariable=degree, width=30).pack( padx=5, pady=5)
        page_name.tree = createTreeview(page_name,lambda:0,extend_num,extend_name,extend_function)
        ttk.Button(page_name, text='查询', command=lambda:SearchPage.search_degree(page_name,degree), style='TButton').pack(padx=5, pady=5)
        page_name.mainloop()


class DeletePage(tk.Frame):
    def __init__(self, root):
        super().__init__(root)
        self.name = tk.StringVar()
        # 删除状态
        self.status = tk.StringVar()
        self.createPage()
        self.click_times = 0  #点击次数,用于判断是否是第一次点击


    def createPage(self):
        # 创建一个容器
        frame = ttk.Frame(self, padding="50")
        frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 设置样式
        style = ttk.Style()
        style.configure('TLabel', font=('宋体', 12))
        style.configure('TButton', font=('宋体', 12))
        
        # 布局控件
        ttk.Label(frame, text='姓名', style='TLabel').grid(row=0, column=0, padx=5, pady=5)
        ttk.Entry(frame, textvariable=self.name, width=30).grid(row=0, column=1, padx=5, pady=5)
        
        ttk.Button(frame, text='查询', command=self.search_Record, style='TButton').grid(row=1, column=0, padx=5, pady=5)
        ttk.Button(frame, text='删除', command=self.delete_Record, style='TButton').grid(row=1, column=1, padx=5, pady=5)
        ttk.Button(frame, text='清空', command=self.clear_All, style='TButton').grid(row=1, column=2, padx=5, pady=5)
        #提示信息
        ttk.Label(frame, textvariable=self.status, style='TLabel').grid(row=2, column=0, columnspan=3, padx=5, pady=5)

    def search_Record(self):
        # 查询记录######################################### 

        flag,tip = DB.DB().searchPersonByname(self.name.get())   #flag代表true/false,tip代表提示信息或数据人物信息
        
        if flag:
            # if len(tip) == 1:
            #     self.status.set('查询成功\n\n姓名:'+tip['name']+'\n\n性别:'+tip['sex']+'\n\n年龄:'+tip['age']+'\n\n生日:'+tip['birthday']+'\n\n地址:'+tip['address']+'\n\n学历:'+tip['degree']+'\n\n电话:'+tip['phone'])
            # else:
                self.status.set('查询成功\n\n姓名:'+tip[self.click_times%len(tip)]['name']+'\n\n性别:'+tip[self.click_times%len(tip)]['sex']+'\n\n年龄:'+tip[self.click_times%len(tip)]['age']+'\n\n生日:'+tip[self.click_times%len(tip)]['birthday']+'\n\n地址:'+tip[self.click_times%len(tip)]['address']+'\n\n学历:'+tip[self.click_times%len(tip)]['degree']+'\n\n电话:'+tip[self.click_times%len(tip)]['phone']+tip[self.click_times%len(tip)]['child'])
                return tip[self.click_times%len(tip)]   #返回查询到的数据,供后续功能引用

        else:
            self.status.set(tip)
        self.click_times += 1    #点击次数加一
        
        # #############################################

    def delete_Record(self):
        # 删除记录#########################################
        flag,tip = DB.DB().deletePerson(self.name.get())   #flag代表true/false,tip代表提示信息或被删除的人物信息
        
        if flag:
            
            self.status.set('删除成功\n\n姓名:'+tip['name']+'\n\n性别:'+tip['sex']+'\n\n年龄:'+tip['age']+'\n\n生日:'+tip['birthday']+'\n\n地址:'+tip['address']+'\n\n学历:'+tip['degree']+'\n\n电话:'+tip['phone']+tip['child'])

        else:
            self.status.set(tip)
        # ##############################################

    def clear_All(self):
        # 清空所有输入框
        self.name.set('')
        self.status.set('清空成功,请重新输入')

class ShowPage(tk.Frame):
    def __init__(self,root):
        super().__init__(root)
        style = ttk.Style()
        style.configure('TLabel', font=('宋体', 12))
        style.configure('TButton', font=('宋体', 12))
        self.status = tk.StringVar(value='')
        self.createPage()

    def createPage(self):
        ttk.Button(self, text='家谱图', command=self.show_Family_Graph,style='TButton',width=30,padding=50).pack(pady=20)
        ttk.Button(self, text='家谱树', command=self.show_Family_Tree,style='TButton',width=30,padding=50).pack(pady=20)
        ttk.Label(self, textvariable=self.status,style='TLabel').pack(pady=20)

    def show_Family_Tree(self):
        ####################################
        '''
        树状图算法
        '''
        self.status.set('暂未开放,敬请期待')
        ######################################

    def show_Family_Graph(self):
        ####################################
        '''
        关系图算法
        '''
        self.status.set('')
        FT.Family_Tree()

        ######################################


class UpdatePage(tk.Frame):
    def __init__(self,root):
        super().__init__(root)

        self.name = tk.StringVar(value='')
        self.sex = tk.IntVar()
        self.birthday = tk.StringVar(value='')
        self.address = tk.StringVar(value='')
        self.degree = tk.StringVar(value='')
        self.phone = tk.StringVar(value='')
        self.child = tk.StringVar(value='')
        # 插入状态
        self.status = tk.StringVar()
        #日期状态
        self.date_status = tk.StringVar(value='如2000-1-1')
        elseflag = 2  #添加两个功能,1为查询,2为修改
        elsename = ['查询','修改']
        function = [self.search_Record,self.update_Record]
        createPage(self,elseflag,elsename,function)
        self.click_times = 0  #点击次数,用于判断是否是第一次点击



    def search_Record(self):
        flag,tip = DB.DB().searchPersonByname(self.name.get())   #flag代表true/false,tip代表提示信息或数据人物信息
        
        if flag:
            # self.name = tk.StringVar(value=tip[self.click_times%len(tip)]['name'])
            # self.sex = tk.IntVar(value=tip[self.click_times%len(tip)]['sex'])
            # self.birthday = tk.StringVar(value=tip[self.click_times%len(tip)]['birthday'])
            # self.address = tk.StringVar(value=tip[self.click_times%len(tip)]['address'])
            # self.degree = tk.StringVar(value=tip[self.click_times%len(tip)]['degree'])
            # self.phone = tk.StringVar(value=tip[self.click_times%len(tip)]['phone'])
            self.status.set('查询成功')
            if tip[self.click_times%len(tip)]['sex'] == '男':
                self.sex.set(0)
                # tip[self.click_times%len(tip)]['sex'] = 0
            if tip[self.click_times%len(tip)]['sex'] == '女':
                self.sex.set(1)
                # tip[self.click_times%len(tip)]['sex'] = 1
            self.birthday.set(tip[self.click_times%len(tip)]['birthday'])
            self.address.set(tip[self.click_times%len(tip)]['address'])
            self.degree.set(tip[self.click_times%len(tip)]['degree'])
            self.phone.set(tip[self.click_times%len(tip)]['phone'])
            self.child.set(tip[self.click_times%len(tip)]['child'])
            self.click_times += 1    #点击次数加一
            return tip[self.click_times%len(tip)]   #返回查询到的数据,供后续功能引用

        else:
            self.status.set(tip)
        self.click_times += 1    #点击次数加一
    
    def update_Record(self):    #修改记录
        
        # uperson = self.search_Record()
        age = 0
        birthday_one = self.birthday.get()
        print('获取到的birthday_one'+birthday_one)
        true_or_false = True # 日期格式是否正确
        try:
            # 尝试计算年龄
            age = datetime.now().year - int(birthday_one.split('-')[0])
            true_or_false = True
        except:
            true_or_false = False
            messagebox.askretrycancel('错误', '日期格式错误,请重新输入')
        if self.sex.get() == 0:
                    uperson = {'name': str(self.name.get()),
                       'sex':  '男',
                       'age': str(age),
                       'birthday': str(self.birthday.get()),
                       'address': str(self.address.get()),
                       'degree': str(self.degree.get()),
                       'phone': str(self.phone.get()),
                       'child': str(self.child.get())
                       }
        else:
                    uperson = {'name': str(self.name.get()),
                       'sex':  '女',
                       'age': str(age),
                       'birthday': str(self.birthday.get()),
                       'address': str(self.address.get()),
                       'degree': str(self.degree.get()),
                       'phone': str(self.phone.get()),
                       'child': str(self.child.get())
                       }
        print('获取到的uperson'+str(uperson))
        # 更新记录#########################################
        if all(value.strip() != "" for value in uperson.values()):    # 判断是否为空,如果为空则提示
            if true_or_false:  # 日期格式正确
                flag,tip = DB.DB().updatePerson(uperson)
                 #flag代表true/false,tip代表提示信息
            else:
                flag,tip = False,'日期格式错误,请重新输入'
        else:
            flag,tip = False,'请输入完整信息'
            messagebox.askretrycancel('错误', '请输入完整信息')
        self.status.set(tip)

    def clear_All(self):
        AddPage.clear_All(self)


class ImportPage(tk.Frame):
    def __init__(self,root):
        super().__init__(root)
        tk.Label(self, text='关于作者:由厘 不哩布 制作').pack()
        self.create_Page()

    def create_Page(self):
        self.import_Button = ttk.Button(self, text='导入数据', command=self.import_Data_append,width=30,padding=50)
        self.import_Button.pack()
        self.exchange_Button = ttk.Button(self, text='替换数据', command=self.import_Data_unappend,width=30,padding=50)
        self.exchange_Button.pack()
        self.export_Button = ttk.Button(self, text='导出数据', command=self.export_Data_csv,width=30,padding=50)
        self.export_Button.pack()
        self.clear_csv_Button = ttk.Button(self, text='清空数据', command=self.clear_All_csv,width=30,padding=50)
        self.clear_csv_Button.pack()


    def import_Data_append(self):
         flag,tip =DB.Import().read_Foreign_info___append()
         tk.messagebox.showinfo('提示', tip)
    def import_Data_unappend(self):
        flag,tip =DB.Import().read_Foreign_info___unappend()
        tk.messagebox.showinfo('提示', tip)
    def export_Data_csv(self):
         flag,tip = DB.Export().export_csvfile()
         tk.messagebox.showinfo('提示', tip)
    def clear_All_csv(self):
        cflag = tk.messagebox.askokcancel('提示', '确定要清空所有数据吗?')
        if cflag:
            cflag,tip = DB.Import().clear_All_csv()
            tk.messagebox.showinfo('提示', tip)

4.数据文件交互DB

主要包含与人员文件csv的交互函数接口以及csv的导入导出接口

import csv
import os
from tkinter import filedialog


personlist=[]   #已有人物列表
addpersonlist=[]      #要添加的人物列表
class DB:
    '''
    数据库,人员处理类,用于处理人员记录,包含添加、删除、查找、更新、排序、导入、导出等操作,用于与personlist列表交互,将数据存入personlist列表中
    '''
    def __init__(self):
        # self.addPerson()            #添加记录
        # self.searchPersonAll()      #查找所有记录
        # self.deletePerson()         #通过姓名删除记录
        # self.updatePerson()         #通过姓名更新记录
        # self.searchPersonByname()   #通过姓名查找记录
        # self.sortPerson_Age()       #通过年龄排序记录
        # self.getCsvHead()           #获取csv文件表头,用于知道有哪些信息
        # self.Person_toDict()        #将输入的记录转化为字典
        self.persondict={}        #人物记录字典

        if Import().counts_Csv() > len(personlist):
            Import().importCsv()        #导入csv文件中的记录到personlist列表中
        #Import().importCsv()

    
    def addPerson(self,Person):
        '''
        添加人员的接口
        :param Person: 人员记录
        :return: True/False,提示信息'''

        self.persondict = Person
        addpersonlist.append(self.persondict)
        personlist.append(self.persondict)

        print(personlist)
        self.persondict = {}        #清空字典
        return True, f'姓名:{Person.get("name")}\n年龄:{Person.get("age")}\n性别:{Person.get("sex")}\n地址:{Person.get("address")}\n电话:{Person.get("phone")}\n添加成功'


    def searchPersonAll(self):
        '''
        查询所有人员记录的接口
        :return: True/False,提示信息'''
        if len(personlist) == 0:
            return False,'暂无信息'
        return True,personlist
    
    def searchPersonByname(self,name):
        '''
        查询同名的接口
        :param name: 姓名
        :return: True/False,提示信息'''
        #####################################
        #查询同名人的接口
        spersons = []    #定义一个空列表,用于存放查询到的记录
        # print(personlist)
        ######################################
        if len(personlist) == 0:
            return False,'暂无信息'
        for i in personlist:
            if i['name'] == name:
                spersons.append(i)
        if len(spersons) != 0:
            print(spersons)
            return True,spersons
        return False,'暂无此人信息'
    
    def searchPersonBydegree(self,degree):
        '''
        查询同学历的接口
        :param degree: 学历
        :return: True/False,提示信息'''
        #####################################
        #查询同学历的接口
        spersons = []    #定义一个空列表,用于存放查询到的记录
        # print(personlist)
        ######################################
        if len(personlist) == 0:
            return False,'暂无信息'
        for i in personlist:
            if i['degree'] == degree:
                spersons.append(i)
        if len(spersons) != 0:
            print(spersons)
            return True,spersons
        return False,'暂无此人信息'
    
    def searchPersonBysex(self,sex):
        '''
        查询同性别的接口
        :param sex: 性别
        :return: True/False,提示信息'''
        #####################################
        #查询同性别的接口
        spersons = []    #定义一个空列表,用于存放查询到的记录
        # print(personlist)
        ######################################
        if len(personlist) == 0:
            return False,'暂无信息'
        for i in personlist:
            if i['sex'] == sex:
                spersons.append(i)
        if len(spersons) != 0:
            print(spersons)
            return True,spersons
        return False,'暂无此人信息'
    

    def deletePerson(self,name):
        '''
        删除人员信息
        :param name: 人员姓名
        :return: True/False,提示信息'''
        if len(personlist) == 0:
            return False,'删除失败,暂无数据'  #返回False和提示信息
        for i in personlist:
            if i['name'] == name:
                dperson = i    #记录被删除的人
                Export().csv_Person_delete(i)   #删除csv文件中的记录
                return True ,dperson     #返回True和被删除的人
        return False,'删除失败,暂无此人'  #返回False和提示信息
    
    def updatePerson(self,person):
        '''
        更新人员信息
        :param person: 人员信息
        :return: True/False,提示信息'''
        if len(personlist) == 0:
            return '更新失败,暂无数据',False
        for i in personlist:
            if i['name'] == person['name']:
                i['age'] = person['age']
                i['sex'] = person['sex']
                i['address'] = person['address']
                i['phone'] = person['phone']
                i['degree'] = person['degree']
                i['birthday'] = person['birthday']
                i['child'] = person['child']
                Export().csv_Person_update()   #更新csv文件中的记录
                return  True,'姓名:{}\n年龄:{}\n性别:{}\n地址:{}\n电话:{}\n学历:{}\n更新成功'.format(i['name'], i['age'], i['sex'], i['address'], i['phone'],i['degree'])
        return False,'更新失败,暂无此人'
    
        

    def sortPerson_Age(self,reverse=True,in_personlist=personlist):
        '''
        按年龄排序
        :param reverse: True为降序,False为升序
        :return: 排序后的列表'''
        in_personlist.sort(key=lambda x: x['age'], reverse=reverse)
        return in_personlist,True
    

    def getCsvHead(self):
        """
        获取csv文件表头
        :return: 表头列表
        """
        try:
            with open('person.csv', 'r',encoding='utf-8') as csvfile:
                reader = csv.reader(csvfile)
                head = next(reader)
                return True,head
        except FileNotFoundError :
            return False,'文件不存在'
                   


class Export:
    '''
    用于将personlist导出数据到csv文件
    '''
    def __init__(self):
        '''
        初始化,将csv文件中的数据导入到personlist列表中
        '''
        if Import().counts_Csv() > len(personlist):
            Import().importCsv()        #导入csv文件中的记录到personlist列表中
        # self.exportCsv()

    def exportCsv(self):
        """
        导出数据到csv文件
        :return: True
        """
        print(personlist)
        with open('person.csv', 'a', newline='', encoding='utf-8') as csvfile:
            
            fieldnames = ['name', 'sex', 'age', 'birthday','address','degree','phone','child']
            #fieldheaders = ['姓名', '性别', '年龄', '生日','地址','学历','电话']
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            if csvfile.tell() == 0:  # 如果文件为空
                writer.writeheader()
            for  i,person in enumerate(addpersonlist):  # 使用 enumerate() 函数,i是索引,person是元素!!!!!!!!!!!!i不能删,否则会报错,enumerate返回的元组
                writer.writerow(person)
            addpersonlist.clear()  # 清空添加人员列表,否则会重复插入
            print('数据导出成功!')
            return True,'数据导出成功!'

    def csv_Person_delete(self,dperson):
        '''
        删除csv文件中的记录
        :param dperson: 要删除的记录
        :return: True
        '''
        # 打开CSV文件并清空内容
        with open('person.csv', mode='w', encoding='utf-8', newline='') as file:
            csv.writer(file)    # 写入空行
        personlist.remove(dperson)
        addpersonlist = personlist.copy()
        with open('person.csv', 'a', newline='', encoding='utf-8') as csvfile:
            
            fieldnames = ['name', 'sex', 'age', 'birthday','address','degree','phone','child']
            #fieldheaders = ['姓名', '性别', '年龄', '生日','地址','学历','电话']
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            if csvfile.tell() == 0:  # 如果文件为空
                writer.writeheader()
            for i, person in enumerate(addpersonlist):  # 使用 enumerate() 函数
                writer.writerow(person)
            addpersonlist.clear()  # 清空添加人员列表,否则会重复插入
        return True,'删除成功'
    
    def csv_Person_update(self):
        '''
        修改csv文件中的记录
        :return: True'''
                # 打开CSV文件并清空内容
        with open('person.csv', mode='w', encoding='utf-8', newline='') as file:
            csv.writer(file)    # 写入空行
        addpersonlist = personlist.copy()
        with open('person.csv', 'a', newline='', encoding='utf-8') as csvfile:
            
            fieldnames = ['name', 'sex', 'age', 'birthday','address','degree','phone','child']
            #fieldheaders = ['姓名', '性别', '年龄', '生日','地址','学历','电话']
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            if csvfile.tell() == 0:  # 如果文件为空
                writer.writeheader()
            for i, person in enumerate(addpersonlist):  # 使用 enumerate() 函数
                writer.writerow(person)
            addpersonlist.clear()  # 清空添加人员列表,否则会重复插入
        return True,'修改成功'
    
    def export_csvfile(self):
        '''
        导出csv文件
        :return: True'''
        # 打开文件选择对话框,选择文件,返回路径
        file_path = filedialog.asksaveasfilename(title="选择保存文件", defaultextension=".csv", filetypes=[("CSV files", "*.csv"), ("All files", "*.*")])
        file_path = file_path.encode('utf-8').decode('utf-8')    # 确保路径字符串正确编码
        file_path = os.path.abspath(file_path)    # 使用os.path模块处理路径
        if file_path:
            addpersonlist = personlist.copy()
            with open(file_path, 'w', newline='', encoding='utf-8') as csvfile:
            
                fieldnames = ['name', 'sex', 'age', 'birthday','address','degree','phone','child']
                #fieldheaders = ['姓名', '性别', '年龄', '生日','地址','学历','电话']
                writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
                if csvfile.tell() == 0:  # 如果文件为空
                    writer.writeheader()
                for  i,person in enumerate(addpersonlist):  # 使用 enumerate() 函数,i是索引,person是元素!!!!!!!!!!!!i不能删,否则会报错,enumerate返回的元组
                    writer.writerow(person)
                addpersonlist.clear()  # 清空添加人员列表,否则会重复插入
                print('数据导出成功!')
                return True,'数据导出成功!'

                





class Import:
    '''
    导入csv文件
    :return: True'''
    def __init__(self):
        
        self.counts_Csv()
        

    def importCsv(self):  # 导入生成的csv文件,获取数据
        ''' 
        读取csv文件,获取数据
        :return: 全局personlist列表,其他函数可直接访问'''
        try:
            with open('person.csv', 'r',encoding='utf-8') as csvfile:
                reader = csv.DictReader(csvfile)
                for row in reader:
                    personlist.append(row)
            print('数据导入成功!')
        except FileNotFoundError:
            print('文件不存在')

    # 读取csv文件,返回总行数
    def counts_Csv(self):
        '''
        读取csv文件,返回总行数
        :return: 总行数'''
        try:
            with open('person.csv', 'r',encoding='utf-8') as csvfile:
                reader = csv.DictReader(csvfile)
                return len(list(reader))
        except FileNotFoundError:
            return 0
        
    #追加模式将外部csv文件数据导入
    def read_Foreign_info___append(self): 
        '''
        打开文件选择对话框,选择文件,返回路径,将文件内容追加到personlist列表中
        :return: 选择了,就True
                发生错误,未选择中途取消,就False'''
        #打开文件选择对话框,选择文件,返回路径
        file_path = filedialog.askopenfilename(title="选择人员文件")
        file_path = file_path.encode('utf-8').decode('utf-8')    # 确保路径字符串正确编码
        file_path = os.path.abspath(file_path)    # 使用os.path模块处理路径
        if file_path:
            # 打开文件,读取内容

            try:
                with open(file_path, 'r',encoding='utf-8') as csvfile:
                    reader = csv.reader(csvfile)
                    head = next(reader)
                    print(head)
            except FileNotFoundError:
                print(f'文件未找到:{file_path}')
                return False,'文件未找到'
            except Exception as e:
                print(f'打开文件时发生错误:{e}')
                return False,'打开文件时发生错误'
            except:
                return False,'文件格式不正确,请选择csv文件'

            if head == ['name', 'sex', 'age', 'birthday', 'address', 'degree', 'phone','child'] or head == ['姓名', '性别', '年龄', '生日', '地址', '学历', '电话','子女']:
                with open(file_path, 'r',encoding='utf-8') as file:
                    reader = csv.DictReader(file)
                    for row in reader:
                        addpersonlist.append(row)
                    #addpersonlist = personlist.copy()
                    print('数据导入::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;')
                    print(addpersonlist)
                    Export().exportCsv()
                    print(addpersonlist)
                    addpersonlist.clear()  # 清空添加人员列表,否则会重复插入
                print('数据导入成功!')
                return True,'导入成功'
            else:
                print('文件格式不正确')
                return False,'文件格式不正确\n列名分别需为:姓名,性别,年龄,生日,地址,学历,电话'
        else:
            print('未选择文件')
            return False,'未选择文件'
        
    def read_Foreign_info___unappend(self):  # 将原来文件内容清空,再导入
        '''
        打开文件选择对话框,选择文件,返回路径,将原来文件内容清空,再导入
        :return: 选择了,就True
                发生错误,未选择中途取消,就False'''
        #打开文件选择对话框,选择文件,返回路径
        file_path = filedialog.askopenfilename(title="选择人员文件")
        file_path = file_path.encode('utf-8').decode('utf-8')    # 确保路径字符串正确编码
        file_path = os.path.abspath(file_path)    # 使用os.path模块处理路径
        if file_path:
            # 打开文件,读取内容

            try:
                with open(file_path, 'r',encoding='utf-8') as csvfile:
                    reader = csv.reader(csvfile)
                    head = next(reader)
            except FileNotFoundError:
                print(f'文件未找到:{file_path}')
                return False,'文件未找到'
            except Exception as e:
                print(f'打开文件时发生错误:{e}')
                return False,'打开文件时发生错误'
            except:
                return False,'文件格式不正确,请选择csv文件'

            if head == ['name', 'sex', 'age', 'birthday', 'address', 'degree', 'phone','child'] or head == ['姓名', '性别', '年龄', '生日', '地址', '学历', '电话','子女']:
                with open('person.csv', mode='w', encoding='utf-8', newline='') as file:
                    csv.writer(file)    # 写入空行,清空文件
                with open(file_path, 'r',encoding='utf-8') as file:
                    reader = csv.DictReader(file)
                    personlist.clear()
                    for row in reader:
                        personlist.append(row)
                        addpersonlist.append(row)
                    Export().exportCsv()
                    addpersonlist.clear()  # 清空添加人员列表,否则会重复插入
                print('数据导入成功!')
                return True,'导入成功'
            else:
                print('文件格式不正确')
                return False,'文件格式不正确\n列名分别需为:姓名,性别,年龄,生日,地址,学历,电话, 子嗣'
        else:
            print('未选择文件')
            return False,'未选择文件'
    def clear_All_csv(self):
        ''' 清空文件内容
        :return: True'''
        header = ['name', 'sex', 'age', 'birthday', 'address', 'degree', 'phone','child']
        with open('person.csv', mode='w', encoding='utf-8', newline='') as file:
            csv.writer(file)    # 写入空行,清空文件
            csv.DictWriter(file, fieldnames=header).writeheader()    # 写入表头
        return True,'清空成功'

        


        

5.Family_Tree 绘制人员关系图

将从DB获取到的数据加工,用plt和networkx绘制为图

import DB as DB
import networkx as nx
import matplotlib.pyplot as plt



class Family_Tree:
    def __init__(self):
        '''
        初始化人员节点和边
        '''
        flag,self.personlist_head = DB.DB().getCsvHead()
        flag,self.personlist = DB.DB().searchPersonAll()
        # 将边转换为元组
        self.person_edges_tuple = [(item['name'],item['child']) for item in self.personlist]

        self.person_nodes = [f"{item['name']}" for item in self.personlist]
        print(self.person_edges_tuple)

        

        self.drawGraph()

    def drawGraph(self):
        '''
        绘制家谱图
        '''
        G = nx.DiGraph()
        # for node in self.person_nodes:
        #     if not G.has_node(node):
        #         G.add_node(node)

        G.add_edges_from(self.person_edges_tuple)
        plt.figure("家谱图")  # 创建一个新的图形窗口,并设置窗口的标题
        # plt.title("家谱图")  # 设置窗口的标题
        # 设置默认字体
        plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
        plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
        nx.draw(G, with_labels=True, node_size=1000, node_color='lightblue', font_size=10, font_weight='bold', arrows=True, arrowsize=20, arrowstyle='->') 

        plt.show()


if __name__ == '__main__':
    Family_Tree()

6.打包

用pyinstaller将以上打包,其中pyinstaller相关操作可以参考

使用 PyInstaller | PyInstaller中文文档 (gitbook.io)

结语

目前还在学习技术,这是本人第一次打包成功一个pythonGUI的简单程序,还有特别多不完善的地方,还会继续努力^_^

基于 PythonTkinter信息管理系统通常是一个用 Python 编程语言构建的应用程序,使用Tkinter库创建图形用户界面(GUI),用于存储、管理、检索和显示数据。这种系统常用于组织联系人信息、项目进度、库存等。 下面是简单介绍如何构建这样的系统: 1. **安装和导入库**:首先确保已安装 PythonTkinter。可以通过命令行运行 `pip install tkinter` 安装。 2. **设计 GUI**:使用 Tkinter 构建窗口(Window)、标签(Label)、文本框(Entry)和按钮(Button)。例如,你可以创建一个表单,包含姓名、地址、电话等字段。 ```python import tkinter as tk root = tk.Tk() root.title("信息管理系统") ``` 3. **数据结构**:可以使用 Python 数据结构(如字典或列表)来存储和管理信息。比如: ```python data = [] def add_entry(): # 添加数据逻辑 ``` 4. **功能实现**:定义函数来处理用户输入,比如添加新条目、查找特定信息、编辑记录等。这可能涉及到数据库操作,如果是大型应用,可能会考虑 SQLite 或其他数据库系统。 5. **事件绑定**:为按钮和其他交互元素绑定事件处理器,如点击事件、键盘输入事件等。 6. **布局管理器**:Tkinter 提供了布局管理器(如 Grid, Pack 或 Place),帮助自动调整控件的位置。 7. **用户体验**:优化用户界面,包括良好的反馈机制、清晰的指示和易于使用的导航。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值