Handsome_zhou 发表于 2020-10-20 11:01:17

Tkinter与shelve结合构建database

本帖最后由 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时才会写入该对象。
    示例:
import shelve

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

d = data            # store data at key (overwrites old data if
                           # using an existing key)
data = d            # retrieve a COPY of data at key (raise KeyError
                           # if no such key)
del d               # delete data stored at key (raises KeyError
                           # if no such key)

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

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

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

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

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

因为shelve可以进行数据的持久化,而tkinter的功能也是非常的丰富,可以很方便的做出一个界面来。那么与tkinter结合起来就可以构建一个可以自由提取和更新数据的数据库了。

上图是数据库界面

上图是输入键值sue之后提取的原始数据库数据

上图是更改sue的年龄之后更新的数据库数据

上图是增加新的键值及数据之后数据库中保存的数据

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

class Person:
    def __init__(self,name,age,pay=0,job=None):
      self.name = name
      self.age= age
      self.pay= pay
      self.job= job

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

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

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

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

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

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

window = makeWidgets()
window.mainloop()
db.close()
页: [1]
查看完整版本: Tkinter与shelve结合构建database