摘 要:随着社会节奏加快、强度增大,人们面临的压力日益增加,缓解焦虑调节心情成为当下迫切需求。本文介绍了一个基于Python和数据库的Mood Diary心情记录系统的设计与实现过程。首先,分析了设计需求,本系统需要数据库和Python的支撑;其次,对数据库和页面进行详细制定了切实可行的结构和模型;再次,验证了心情记录系统在在数据库应用与开发方面的可行性和实际效果;最后,对心情记录系统进行总结与展望,为之后的同类型系统设计提供了经验与挑战。
关键词:Python、数据库、Mood Diary心情记录系统
1.引言
由于现在社会节奏越来越快,强度不断增加,带来的压力越来越大,如何缓解焦虑、调节心情成为了一个时兴的需求。为了满足这一需求,本系统使用Python和数据库开发了一款Mood Diary心情记录系统。本系统设有注册与登录页面,注册完成即可进行登录操作。登录后有“新建”、“我的”两大功能,“新建”能选契合心情照片、自填文案并保存当下情绪;“我的”可查阅过往记录,含记录时间、内容及对应心情照片。提供了一种便利的方式来记录个人心情变化,有助于用户更好地了解自己的情绪波动。旨在充分发挥数据库在其开发中的作用,提高系统的性能、稳定性以及用户体验,通过可视化的页面完成对数据库的增加、删除、修改和查询操作。
2.设计需求
设计一个系统需要满足可视化、功能性两大方面,可以将数据库和Python的tkinter模块结合实现。Mood Diary心情记录系统需要对用户登录、新建心情记录、修改情绪波动、回顾历史四种功能进行设计,如图2-1设计需求所示。

图2-1 设计需求
2.1数据库设计需求
数据库设计的核心在于对用户信息增删改查功能的高效实现,确保信息的及时性、准确性和完整性。本系统需要建立一个专门的数据库,用于存放用户的所有数据。
2.1.1用户信息数据库
在用户登录功能中需要对用户注册信息进行留痕,将注册过的用户名和用户密码添加在一个表格里,表格需要有用户姓名和用户密码两个原子项,只有在此表格中相对应的用户名和用户密码才可以登录到系统中,保障了系统的安全性与私密性。
2.1.2内容统计数据库
在回顾历史功能中要实现对该用户以前创建的所有心情记录进行展示,因此需要一个记录表格,此表格以用户名、时间、照片、文案为原子项。在回顾历史时,只需要提取用户名,查找该用户名的所以记录用于展示。
2.2页面设计需求
页面设计的核心在于提供用户友好的图形化界面,使用户可以更直观的进行操作。本系统需要对用户登录页面、主页面、新建页面、历史页面进行设计。
2.2.1用户登录页面
用户登录页面用于确定用户身份和区分用户角色,其核心功能是验证用户输入的用户名和密码信息,确定其身份的合法性。没有注册的用户注册后才可登录,注册过的用户输入正确的用户名和密码即可进入系统。
2.2.2主页面
主页面标题要显示用户姓名,让用户双重确定账号的正确性与私密性。主页面主要是展示“新建”与“我的”两大功能,为新建页面和历史页面做准备。让用户更加直观、便利的找到自己要进行的操作。
2.2.3新建页面
新建页面要完成对心情图片的选择和文案的编写。需要对表示心情的十四张图片逐条展示,可通过按钮调节选择第几张图片,在写完文案后点击确定即新建成功。
2.2.4历史页面
历史页面需要对该用户的历史心情记录进行全展示。以时间为标准倒叙展示,通过按钮调节依次观看历史记录,分别展示时间、文案、图片。
2.3 Python与数据库的连接
Python的tkinter模块可实现界面的可视化,数据库可用于记录数据,二者相结合可实现系统的功能化。使用python连接sqlite3模块,可在python中进行数据库语句的操作,完成数据库的创建、数据表的增删改查等操作,通过Navicat Premium 16可看到建立的数据库、数据表。
2.3.1用户信息数据库
用户登录页面中,输入用户名和用户密码,点击“注册”按钮,自动提取用户名和密码插入用户信息数据库中。
2.3.2内容统计数据库
在新建页面中,选择好表示心情是图片、编辑好文案,点击“确定”按钮,自动提取用户名、实时时间、照片路径、文案,插入到内容统计数据库中。
2.4 其他设计需求
为了使本系统更加具有真实感和人性化,在新建操作时需要对十四个表示心情的图片进行选择和对确定记录心情时间继续实记。
2.4.1图片展示
把十四张表示心情的照片和运行文件放于同于根目录[1],如图2-2 目录所示。导入glob模块,对图片文件进行访问,导入PIL的Image和ImageTk模块对图片进行展示,如图2-3 feel_photos所示。

图2-2 目录

图2-3 feel_photos
2.4.2时间记录
导入datetime模块,当点击“确定”按钮时,就对此刻年月日精确到秒进行实际,并放入数据表中便于读取。
3.数据库设计
建立“user_data”数据库,用于存放用户数据。如图3-1 python连接数据库“user_data”语句所示,python连接sqlite3连接数据库,无则创建,有则连接。连接后的结果,如图3-2 Navicat Premium 16数据库“user_data”可视化所示,通过Navicat Premium 16查看。

图3-1 python连接数据库“user_data”语句

图3-2 Navicat Premium 16数据库“user_data”可视化
3.1用户管理设计
在“user_data”数据库下,建立“UserHome”数据表,以username、password为原子项。如图3-3 python创建表“UserHome”语句所示,python连接sqlite3,create table语句创建数据表。创建后的结果,如图3-4 Navicat Premium 16数据表“UserHome”可视化所示,通过Navicat Premium 16查看。

图3-3 python创建表“UserHome”语句

图3-4 Navicat Premium 16数据表“UserHome”可视化
3.2内容管理设计
在“user_data”数据库下,建立“self_daily”数据表,以username、time、photo、words为原子项。如图3-5 python创建表“self_daily”语句所示,python连接sqlite3[2],create table语句创建数据表。创建后的结果,如表3-6 Navicat Premium 16数据表“slef_daily”可视化所示,通过Navicat Premium 16查看。

图3-5 python创建表“self_daily”语句
表3-6 Navicat Premium 16数据表“slef_daily”可视化

“user_data”数据库结构如图3-7所示。

图3-7 “user_data”数据库结构图
4.页面设计
4.1登录页面设计
在Python中导入PIL中的Image, ImageTk模块使图片加载到界面上,导入tkinter制作登录界面[3],包括“用户名称”、“账号密码”、“自动填写”、“登录”和“注册”Button,以及用户名称、账号密码的Entry,如图4-1登录页面所示。

图4-1 登录页面
新用户在填写完用户名称、账号密码后点击“注册”,系统会弹出“注册成功”页面,如图4-2 注册所示,并自动提取用户名和密码插入到数据表“UserHome”中,如表4-3 “UserHome”的增前、表4-4 “UserHome”的增后所示,再点击“登录”按钮即可进入。

图4-2 注册
表4-3 “UserHome”的增前

表4-4 “UserHome”的增
老用户若填写不正确的用户名称、账号密码后点击“注册”,系统会弹出“错误”界面,如图4-5 登录失败所示;老用户若填写正确的用户名称、账号密码后点击“注册”,系统会弹出“登录成功”界面,如图4-6 登录成功所示。

图4-5 登录失败

图4-6 登录成功
4.2心情日记系统主界面设计
在Python中导入PIL中的Image, ImageTk模块使图片加载到主界面上,导入tkinter制作主界面,包括“新建”、“我的”Button,以及根据用户名命名的text,如图4-7 欢迎YJJ、4-8 欢迎向未来所示。

图4-7 欢迎YJJ

图4-8 欢迎向未来
4.3新建界面设计
点击“新建”Button,弹出“Feel Window”页面。导入glob模块获取图片路径:PIL模块的Image、ImageTk,用于循环播放“feel_photos”的12张照片;导入datetime模块,用于记录时间。该界面包括“上一张”、“确定”、“下一张”Button,以及文本框text,如图4-9 新建页面所示。通过“上一张”、“下一张”按钮可以选择所对应的心情的图片,在文本框里写下想说的话,点击“确定”,如图4-10确定页面所示,就会get用户姓名、时间、图片路径、文本框里的话插入到数据表“self_daily”中,如表4-11 表“self_daily”插入所示,并且返回到主界面。

图4-9 新建页面

图4-10 确定页面
表4-11 表“self_daily”插入

4.4我的界面设计
点击“我的”Button,弹出“My History”页面。该界面包括“上一张”、“确定”、“下一张”Button,以及文本框text,如图4-12 我的页面所示。通过“上一张”、“下一张”按钮可以看过往心情记录,按照时间逆序,如图4-13 历史记录1、4-14 历史记录2所示。

图4-12 我的页面

图4-13 历史记录1

图4-14 历史记录2
5.功能测试
5.1系统的增操作
5.1.1用户的增操作
对数据库“user_data”中表“UserHome”。当注册新用户时,如图5-1 新注册所示,会自动提取用户姓名和账号密码插入到表“UserHome”中,如表5-2 “UserHome”表原表、表5-3 “UserHome”表新插入所示、图5-4 python“UserHome”插入代码所示。

图5-1 新注册
表5-2 “UserHome”表原表

表5-3 “UserHome”表新插入


图5-4 python“UserHome”插入代码
5.1.2内容的增操作
对数据库“user_data”中表“self_daily”。当用户选好心情、编辑好文案、点击确认时,如图5-5 新心情所示,会自动提取用户名、时间、照片路径、文案插入到表“self_daily”中,如表5-6“self_daily”表原表、表5-7“self_daily”表新插入所示、图5-8 python“self_daily”插入代码所示。

图5-5 新心情
表5-6 “self_daily”表原表

表5-7 “self_daily”表新插入


图5-8 python“self_daily”插入代码
5.2系统的删操作
考虑到心情只会改变不会消失,没有设定删除按钮操作。但是如果对表“UserHome”删除一组元组,如表5-9 表“UserHome”删除前、表5-10表“UserHome”删除后所示,那需要该用户重新注册,才能登录,如图5-11 无对应信息。
表5-9 表“UserHome”删除前

表5-10表“UserHome”删除后


图5-11 无对应信息
5.3系统的改操作
对数据库“user_data”中表“UserHome”。当老用户注册时,如图5-12 老用户注册所示,会自动修改原列表中的密码,如表5-13 “UserHome”表、表5-14 “UserHome”表新修改所示、图5-15 python“UserHome”修改代码所示。

图5-12 老用户注册
表5-13 “UserHome”表

表5-14“UserHome”表新修改


图5-15 python“UserHome”修改
5.4系统的查操作
5.4.1 登录的查操作
登录时的用户名称和账号密码必须为表“UserHome”的同一元组内容,如图5-16 python代码登录的查操作所示。当输入“YJJ”,“1111”时就会显示错误,如图5-17 登录错误页面所示。

图5-16 python代码登录的查操作

图5-17 登录错误页面
5.4.2 历史记录的查操作
“我的”按钮中,“My History”页面,要提取用户名,查找该用户名所以记录,如图5-18 python代码我的历史的查操作所示。提取内容如表5-19 “self_daily”提取内容所示。

图5-18 python代码我的历史的查操作
表5-19 “self_daily”提取内容

总结与展望
本文通过对Python和数据库共同实现的Mood Diary心情记录系统进行了详细的介绍和功能实现。在系统开发中,考虑了数据库、数据表的设计、界面的布局、数据库操作语句的优化等问题,以确保系统的稳定性、用户友好性和数据安全性。在全面的功能测试、性能测试和安全性测试中,实验结果表明系统在数据库层面达到了稳定、高效的运行状态,为用户提供了优质的体验。未来随着规模的增加,将会有更多用户即有更多的数据,需要更加关注系统的拓展性和容错性。增加系统的安全性,通过采用先进的加密技术和强化权限控制手段,确保用户数据得到最佳的保护。
总而言之,Mood Diary心情记录系统在设计与实现中取得了令人满意的成果。数据库技术处于持续演变之中,需要我们时刻关注并不断进行优化。让用户更加舒适、自得的写下自己的心情,缓解自己的情绪。
参考文献:
[1]Python GUI界面设计教学:制作一个图片查看器(上)https://b23.tv/yrhCLXn
[2]苏虹,王鹏远,李萍.Python程序设计[M].中国铁道出版社:202302.324.
[3]冯桂尔.基于Python的GUI(Tkinter)实例开发[J].信息与电脑(理论版),2023,35(01):175-178.
import tkinter as tk
from tkinter import *
import glob
import tkinter.messagebox
from PIL import Image, ImageTk
import sqlite3
import os
from datetime import datetime
class MainApp:
def __init__(self):
# 连接到SQLite数据库,如果不存在则创建
self.conn = sqlite3.connect('user_data.db')
self.cursor = self.conn.cursor()
# 创建数据表UserHome(如果不存在)
self.cursor.execute('create table if not exists UserHome(username text,password text)')
self.conn.commit()
# 根背景
self.root = tk.Tk()
self.root.title('Mood Diary')
self.root.geometry('275x290')
photos = glob.glob('photo/photo1.jpg')
if photos:
photo = ImageTk.PhotoImage(Image.open(photos[0]))
self.photo_label = tk.Label(self.root, image=photo, width=400, height=400)
self.photo_label.image = photo
self.photo_label.pack()
# 用户名
self.labelName = Label(self.root, text='用户名称:')
self.labelName.place(x=35, y=35)
self.entryName = Entry(self.root)
self.entryName.place(x=120, y=35, width=100)
# 密码
self.labelPwd = Label(self.root, text='账号密码:')
self.labelPwd.place(x=35, y=100)
self.entryPwd = Entry(self.root, show='*')
self.entryPwd.place(x=120, y=100, width=100)
# 登录按钮
self.buttonlogin = Button(self.root, text='登录', command=self.login)
self.buttonlogin.place(x=55, y=200, width=50)
# 注册按钮
self.buttonzhuce = Button(self.root, text='注册')
self.buttonzhuce.place(x=150, y=200, width=50)
self.buttonzhuce.config(command=self.register)
# 自动填写按钮
self.button_auto_fill = Button(self.root, text='自动填写', command=self.auto_fill)
self.button_auto_fill.place(x=90, y=150, width=80)
#登录
def login(self):
username = self.entryName.get()
password = self.entryPwd.get()
self.cursor.execute("select * "
"from UserHome "
"where username=? and password=?",
(username, password))
result = self.cursor.fetchone()
if result:
tkinter.messagebox.showinfo("登录成功", "登录成功,欢迎回来!")
self.open_welcome_page()
else:
tkinter.messagebox.showerror("错误", "用户名或者密码错误,请重新输入!")
#注册
def register(self):
username = self.entryName.get()
password = self.entryPwd.get()
# 检查用户名是否已存在
self.cursor.execute("select * "
"from UserHome "
"where username =?"
, (username,))
existing_user = self.cursor.fetchone()
if existing_user:
# 如果用户名已存在,更新密码
self.cursor.execute("update UserHome "
"set password =? "
"where username =?",
(password, username))
self.conn.commit()
tkinter.messagebox.showinfo(title="注册成功", message="密码已更新!")
else:
# 如果用户名不存在,插入新用户
self.cursor.execute("insert into UserHome (username, password) values (?,?)", (username, password))
self.conn.commit()
tkinter.messagebox.showinfo(title="注册成功", message="注册成功,请登录!")
#自动填写
def auto_fill(self):
self.entryName.insert(0, "YJJ")
self.entryPwd.insert(0, "654320")
#欢迎光临界面
def open_welcome_page(self):
self.welcome_window = tk.Toplevel(self.root)
username = self.entryName.get()
self.welcome_window.title(f"欢迎{username}")
self.welcome_window.geometry('275x290')
new_photos = glob.glob('photo/photo1.jpg')
if new_photos:
photo = ImageTk.PhotoImage(Image.open(new_photos[0]))
photo_label_welcome = tk.Label(self.welcome_window, image=photo, width=400, height=400)
photo_label_welcome.image = photo
photo_label_welcome.pack()
#新建
self.buttoncreate = Button(self.welcome_window, text='新建', command=self.create)
self.buttoncreate.place(x=110, y=100, width=50)
#我的
self.buttonhistory = Button(self.welcome_window, text='我的', command=self.history)
self.buttonhistory.place(x=110, y=150, width=50)
#新建
def create(self):
self.feel_window = FeelWindow(self)
#我的
def history(self):
self.history_window = HistoryWindow(self)
def run(self):
self.root.mainloop()
self.conn.close()
#新建entry FeelWindow
class FeelWindow:
def __init__(self, main_app):
self.main_app = main_app
self.current_photo_index = 0
# 创建新窗口feel_window
self.feel_window = tk.Toplevel(self.main_app.root)
self.feel_window.title('Feel Window')
self.feel_window.geometry('500x500')
# 获取feel_photos目录下的png文件
self.photo_folder = "feel_photos"
self.photo_files = glob.glob(os.path.join(self.photo_folder, "*.png"))
if self.photo_files:
photo_path = self.photo_files[self.current_photo_index]
photo = ImageTk.PhotoImage(Image.open(photo_path))
self.photo_label = tk.Label(self.feel_window, image=photo)
self.photo_label.image = photo
self.photo_label.pack()
# 创建上一张和下一张按钮
self.prev_button = Button(self.feel_window, text='上一张', command=self.prev_photo)
self.prev_button.place(x=150, y=270)
self.next_button = Button(self.feel_window, text='下一张', command=self.next_photo)
self.next_button.place(x=300, y=270)
self.OK_button = Button(self.feel_window, text='确 定')
self.OK_button.place(x=230, y=270)
self.OK_button.config(command=self.on_ok_click)
# 创建写话框
self.text_box = tk.Text(self.feel_window)
self.text_box.place(x=50, y=320, width=400, height=150)
#上一张
def prev_photo(self):
self.current_photo_index = (self.current_photo_index - 1) % len(self.photo_files)
photo_path = self.photo_files[self.current_photo_index]
photo = ImageTk.PhotoImage(Image.open(photo_path))
self.photo_label.config(image=photo)
self.photo_label.image = photo
#下一张
def next_photo(self):
self.current_photo_index = (self.current_photo_index + 1) % len(self.photo_files)
photo_path = self.photo_files[self.current_photo_index]
photo = ImageTk.PhotoImage(Image.open(photo_path))
self.photo_label.config(image=photo)
self.photo_label.image = photo
#确定
def on_ok_click(self):
username = self.main_app.entryName.get()
time_now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
photo_path = self.photo_files[self.current_photo_index]
words = self.text_box.get("1.0", tk.END).strip()
# 将数据插入到数据表self_daily
conn = sqlite3.connect('user_data.db')
cursor = conn.cursor()
cursor.execute("create table if not exists self_daily("
"username text,"
"time text,"
"photo text,"
"words text)")
cursor.execute("insert into self_daily ("
"username, "
"time, "
"photo, "
"words) "
"values (?,?,?,?)",
(username, time_now, photo_path, words))
conn.commit()
conn.close()
self.feel_window.destroy()
#我的entry HistoryWindow
class HistoryWindow:
def __init__(self, main_app):
self.main_app = main_app
# 创建新窗口history_window
self.history_window = tk.Toplevel(self.main_app.root)
self.history_window.title('My History')
self.history_window.geometry('300x320')
username = self.main_app.entryName.get()
self.conn = sqlite3.connect('user_data.db')
self.cursor = self.conn.cursor()
# 查找self_daily数据库中username是用户名的所有记录
query = (f"select time, photo, words "
f"from self_daily "
f"where username='{username}' "
f"order by time desc")
self.cursor.execute(query)
self.all_records = self.cursor.fetchall()
self.total_records = len(self.all_records)
self.current_page = 0
self.time_label = tk.Label(self.history_window, text="")
self.words_label = tk.Label(self.history_window, text="")
self.image_label = tk.Label(self.history_window)
self.show_page(0)
self.time_label.pack()
self.words_label.pack()
self.image_label.pack()
self.prev_button = tk.Button(self.history_window, text="上一次", command=lambda: self.show_page(self.current_page - 1))
self.next_button = tk.Button(self.history_window, text="下一次", command=lambda: self.show_page(self.current_page + 1))
self.prev_button.pack()
self.next_button.pack()
#对应图片展示
def show_page(self, page):
if 0 <= page < self.total_records:
self.current_page = page
record = self.all_records[self.current_page]
self.time_label.config(text=f"{record[0]}")
# 加载并显示图片
try:
image_path = record[1]
for i in image_path:
if i == '\\':
i = '/'
image = Image.open(image_path)
image = image.resize((200, 200))
photo_image = ImageTk.PhotoImage(image)
self.image_label.config(image=photo_image)
self.image_label.image = photo_image
except Exception as e:
print(f"加载图片出错: {e}")
self.words_label.config(text=f"{record[2]}")
if __name__ == "__main__":
app = MainApp()
app.run()
1497

被折叠的 条评论
为什么被折叠?



