鱼C论坛

 找回密码
 立即注册
查看: 1743|回复: 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时才会写入该对象。
    示例:
import shelve

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

d[key] = data              # store data at key (overwrites old data if
                           # using an existing key)
data = d[key]              # retrieve a COPY of data at key (raise KeyError
                           # if no such key)
del d[key]                 # 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'] = [0, 1, 2]        # this works as expected, but...
d['xx'].append(3)          # *this doesn't!* -- d['xx'] is STILL [0, 1, 2]!

# 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结合起来就可以构建一个可以自由提取和更新数据的数据库了。
a.png
上图是数据库界面
b.png
上图是输入键值sue之后提取的原始数据库数据

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

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

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

代码如下:
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[label] = 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]                      #使用key获取数据,并在GUI中显示
    except: #发生异常时执行的代码
        showerror(title='Error', message='No such key!')  #异常处理,弹出error窗口,显示No such key!
    else:  #没有异常时执行的代码
        for field in fieldnames:
            entries[field].delete(0, END)
            entries[field].insert(0, repr(getattr(record, field)))

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

window = makeWidgets()
window.mainloop()
db.close()
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-1-11 00:13

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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