鱼C论坛

 找回密码
 立即注册
查看: 1875|回复: 0

[学习笔记] Tkinter与shelve结合构建database

[复制链接]
发表于 2020-10-20 11:01:17 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 Handsome_zhou 于 2020-10-20 11:10 编辑

"Shelf" 是一种持久化的类似字典的对象。 与 "dbm" 数据库的区别在于 Shelf 中的值(不是键!)实际上可以为任意 Python 对象 --- 即 pickle 模块能够处理的任何东西。 这包括大部分类实例、递归数据类型,以及包含大量共享子对象的对象。 键则为普通的字符串。
shelve.open(filename, flag='c', protocol=None, writeback=False)
    打开一个持久化字典。filename指定下层数据库的基准文件名。默认情况下,下层数据库会以读写模式打开。默认会使用第三版pickle协议来序列化值。pickle协议版本可通过protocol形参来指定。
    由于Python的语义的限制,Shelve对象无法确定一个可变的持久化字典条目在何时被修改。默认情况下,只有在被修改对象再复制给shelve时才会写入该对象。
    示例:
  1. import shelve

  2. d = shelve.open(filename)  # open -- file may get suffix added by low-level
  3.                            # library

  4. d[key] = data              # store data at key (overwrites old data if
  5.                            # using an existing key)
  6. data = d[key]              # retrieve a COPY of data at key (raise KeyError
  7.                            # if no such key)
  8. del d[key]                 # delete data stored at key (raises KeyError
  9.                            # if no such key)

  10. flag = key in d            # true if the key exists
  11. klist = list(d.keys())     # a list of all existing keys (slow!)

  12. # as d was opened WITHOUT writeback=True, beware:
  13. d['xx'] = [0, 1, 2]        # this works as expected, but...
  14. d['xx'].append(3)          # *this doesn't!* -- d['xx'] is STILL [0, 1, 2]!

  15. # having opened d without writeback=True, you need to code carefully:
  16. temp = d['xx']             # extracts the copy
  17. temp.append(5)             # mutates the copy
  18. d['xx'] = temp             # stores the copy right back, to persist it

  19. # or, d=shelve.open(filename,writeback=True) would let you just code
  20. # d['xx'].append(5) and have it work as expected, BUT it would also
  21. # consume more memory and make the d.close() operation slower.

  22. d.close()                  # close it
复制代码

使用shelve时不要依赖shelve的自动关闭功能,使用结束时应该显式的调用close()。

因为shelve可以进行数据的持久化,而tkinter的功能也是非常的丰富,可以很方便的做出一个界面来。那么与tkinter结合起来就可以构建一个可以自由提取和更新数据的数据库了。
a.png
上图是数据库界面
b.png
上图是输入键值sue之后提取的原始数据库数据

上图是对sue的年龄修改后数据库中更新后的数据

上图是对sue的年龄修改后数据库中更新后的数据

上图是更改sue的年龄之后更新的数据库数据
d.png
上图是增加新的键值及数据之后数据库中保存的数据

代码如下:
  1. from tkinter import *
  2. from tkinter.messagebox import showerror
  3. import shelve
  4. fieldnames = ('name','age','job','pay')

  5. class Person:
  6.     def __init__(self,name,age,pay=0,job=None):
  7.         self.name = name
  8.         self.age  = age
  9.         self.pay  = pay
  10.         self.job  = job

  11. if __name__ == '__main__':
  12.     bob = Person('Bob Smith',42,30000,'software')
  13.     sue = Person('Sue Jones',45,40000,'hardware')

  14. db = shelve.open('class-shelve')
  15. db['bob'] = bob
  16. db['sue'] = sue

  17. #定义函数
  18. def makeWidgets():
  19.     global entries    #声明entries为全局变量
  20.     window = Tk()     #创建根窗口
  21.     window.title('People Shelve')
  22.     form = Frame(window) #控键在屏幕上显示一个矩形区域,多用来作为容器   ,这里的根窗口相当与变为form
  23.     form.pack()    #框架打包
  24.     entries = {}    #创建entries字典

  25.     for (ix, label) in enumerate(('key',) + fieldnames):      #for 索引,值  在元组中,元组中的值比原fildnames增加一个'key'
  26.         lab = Label(form, text=label)  #把标签显示在矩形区域内,赋给变量lab
  27.         ent = Entry(form)   #把矩形区域输入的值赋给变量ent
  28.         lab.grid(row=ix, column=0)   #把标签放在第一列
  29.         ent.grid(row=ix, column=1,padx=10,pady=5)   #把输入值放在第二列
  30.         entries[label] = ent         #为字典对应的键赋值
  31.     Button(window, text="Fetch",  command=fetchRecord).pack(side=LEFT)
  32.     Button(window, text="Update", command=updateRecord).pack(side=LEFT)
  33.     Button(window, text="Quit",   command=window.quit).pack(side=RIGHT)
  34.     return window

  35. #应用函数fetchrecord
  36. def fetchRecord():
  37.     key = entries['key'].get()
  38.     try:   #执行代码
  39.         record = db[key]                      #使用key获取数据,并在GUI中显示
  40.     except: #发生异常时执行的代码
  41.         showerror(title='Error', message='No such key!')  #异常处理,弹出error窗口,显示No such key!
  42.     else:  #没有异常时执行的代码
  43.         for field in fieldnames:
  44.             entries[field].delete(0, END)
  45.             entries[field].insert(0, repr(getattr(record, field)))

  46. #应用函数updaterecord
  47. def updateRecord():
  48.     key = entries['key'].get()
  49.     if key in db:
  50.         record = db[key]                      #更新已有记录
  51.     else:
  52.         #在该键下生成/保存新记录
  53.         record = Person(name='?', age='?')    #字符串用引号引起来
  54.     for field in fieldnames:
  55.         setattr(record, field, eval(entries[field].get()))
  56.     db[key] = record

  57. window = makeWidgets()
  58. window.mainloop()
  59. db.close()
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-27 10:03

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表