# 20254121 2025-2026-2 《Python程序设计》实验4报告
课程:《Python程序设计》
班级: 2541
姓名: 何若水
学号:20254121
实验教师:王志强
实验日期:2026年5月19日
必修/选修: 专选课
1.实验内容
Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。
例如:编写从社交网络爬取数据,实现可视化舆情监控或者情感分析。
例如:利用公开数据集,开展图像分类、恶意软件检测等
例如:利用Python库,基于OCR技术实现自动化提取图片中数据,并填入excel中。
例如:爬取天气数据,实现自动化微信提醒
例如:利用爬虫,实现自动化下载网站视频、文件等。
例如:编写小游戏:坦克大战、贪吃蛇、扫雷等等
注:在Windows/Linux系统上使用VIM、PDB、IDLE、Pycharm等工具编程实现。
2. 实验过程及结果
(一)实验分析
1.实验目的
本次实验作为Pthon知识点的综合应用,需要熟练运用多个知识点来实现多个功能。恰巧我作为一个诗词爱好者,一直期待着拥有一个自己的诗词小程序,来记录我感兴趣的作品。为了将兴趣与实验相结合,并清晰展示不同功能,我决定使用PyCharm编程代码,制作一个可以和用户交互的古诗词学习系统。
2.预期功能
a.输入诗词标题,查询诗词原文;
b.输入诗词标题,学习赏析诗词意境、风格;
c.每日向用户随机推荐诗词名句,增加文学涵养;
d.支持用户推荐未收录诗词,并在留言板中展示;
e.帮助用户按特定主题(如风格)浏览诗词;
f.按时间顺序介绍历代著名诗/词人生平;
g.为庆祝长征胜利90周年,设专栏收录主席著名诗词,供用户学习其革命乐观主义与革命浪漫主义精神。
3.主要功能原理
a.使用面向对象程序设计中类的定义与实例化、init 构造,分装数据、界面;
b.采用Tkinter框架实现GUI图形化界面,实现程序的可视化;
c.制作外部读写JSON文件,存储供查询、赏析以及推荐的诗词相关资料;
d.运用random模块中的不同函数,做到随机挑选名句;
e.加入异常处理,防止程序因为文件缺失等原因而崩溃出错;
f.编写datetime.now().strftime("%Y-%m-%d")字符串,实时获取时间,从而每日推荐不同名句。
(二)实验过程
1.搭建GUI框架,结合并类的定义与实例化、init 构造,确定颜色搭配、字体大小与样式,同时划分出六大主要功能板块:“古诗词查询”、“古诗词赏析”、“每日诗词推荐”(合并名句推荐与留言推荐)、“诗海寻珠”(按照特定主体浏览诗词)、“山花烂漫”(主席诗词收录)、“诗人漫步”(诗人/词人生平介绍);(此处代码过多,故只展示部分)


2.找到开学初创建的Python专用文件夹,以“文本文档”格式新建文件,再以“记事本”方式打开该文件,然后输入资料,包括诗词原文、赏析内容、著名诗句、诗人生平,按下Ctrl+S保存文件,然后关闭记事本,从而构建一系列外部读写JSON文件。然后返回PyCharm,重新命名文件,去掉后缀“.txt”,把他们变成完全的JSON格式;


3.开始编写诗词查询与赏析功能模块。使用load_poems_db()和load_appreciate_db()方法,以实现用户输入诗名后,程序根据当前模式从对应JSON文件中检索,并显示搜索结果。为了提升用户使用体验,不必多次输入诗名,于是使用模式变量 current_mode 分流,做到查询与赏析共用输入框与内容显示区;(此处代码过多,故只展示部分)



4.继续编写名句推荐与留言推荐模块。首先运用datetime.now().strftime("%Y-%m-%d")字符串,实时获取时间,然后再加入函数random.seed(today_str)与函数random.choice(self.daily_quotes),从而把随机名句推荐与每日日期建立起关系,同时提供输入框,供用户留言,并把建议显示在页面上;(此处代码过多,故只展示部分)


5.在“诗海寻珠”这一模块中,我选择使用标签映射技术。用户通过点击主题标签,系统可以自动从中JSON文件中匹配并展示相关诗词,完成按照特定主体浏览诗词的功能;(此处代码过多,故只展示部分)


6.对于特别专栏“山花烂漫”,首先,定义self.card_frame卡片容器,然后再通过Canvas+Scrollbar+create_window 实现这些卡片可滚动,最后,再以bind("



7.最后,我在“诗人漫步”模块中模拟了翻页书的形式,用户点击上一页/下一页就可以翻页到下一位诗人。通过构建序列self.poets_list,按照时间顺序存储诗人顺序,再通过使用索引current_poet_index,用来记录当前停留在哪一页,初步完成翻页框架。之后加入if函数,用户点击上一页/下一页时,由if函数判断该页是否处于第一页/最后一页,如果不是的话,由current_poet_index加减1,从而顺利翻页,show_current_poet()刷新显示新的诗人;如果是的话,则出现弹窗提示,防止系统出错。最终,加入Label 组件self.page_label,显示页码,实现翻页书的效果。(此处代码过多,故只展示部分)



8.以下是代码运行视频:
【实验四自编代码运行演示-哔哩哔哩】 https://b23.tv/qJY6JuA
9.以下是完整代码:(仅包含主体代码,不包含JSON文件)
点击查看代码
import tkinter as tk
from tkinter import messagebox, scrolledtext
import json
import os
import random
from datetime import datetime
class PoetryGame:
def __init__(self):
self.root = tk.Tk()
self.root.title("古诗词互动小游戏 - 诗境游")
self.root.geometry("950x650")
self.root.configure(bg='#f0f0f0')
# 加载数据
self.poems_db = self.load_poems_db()
self.appreciate_db = self.load_appreciate_db()
self.mao_poems = self.load_mao_poems()
self.recommend_notes = self.load_recommend_notes()
self.daily_quotes = self.load_daily_quotes() # 新增:加载名句库
# 诗人数据
self.poets_list = []
self.poets_data = {}
self.current_poet_index = 0
self.load_poets()
# 今日推荐(名句版)
self.today_quote = self.get_today_quote()
# UI 状态
self.in_card_view = False
self.create_widgets()
# ================== 数据加载 ==================
def load_poems_db(self):
try:
with open('poems_db.json', 'r', encoding='utf-8') as f:
return json.load(f)
except:
return {"静夜思": {"author": "李白", "dynasty": "唐", "content": "床前明月光"}}
def load_appreciate_db(self):
try:
with open('appreciate_db.json', 'r', encoding='utf-8') as f:
return json.load(f)
except:
return {}
def load_mao_poems(self):
try:
with open('mao_poems.json', 'r', encoding='utf-8') as f:
return json.load(f)
except:
return {"贺新郎·读史": {"author": "主席", "content": "示例", "background": ""}}
def load_recommend_notes(self):
try:
with open('recommend_notes.json', 'r', encoding='utf-8') as f:
return json.load(f)
except:
return []
def load_daily_quotes(self):
"""加载每日名句库"""
try:
with open('daily_quotes.json', 'r', encoding='utf-8') as f:
return json.load(f)
except:
# 如果文件不存在,返回一个默认名句
return [{
"quote": "床前明月光,疑是地上霜。",
"source": "静夜思",
"author": "李白",
"dynasty": "唐",
"tags": ["思乡", "月亮"]
}]
def save_recommend_notes(self):
with open('recommend_notes.json', 'w', encoding='utf-8') as f:
json.dump(self.recommend_notes, f, ensure_ascii=False, indent=2)
def load_poets(self):
try:
with open('poets_index.json', 'r', encoding='utf-8') as f:
index = json.load(f)
self.poets_list = list(index.keys())
for name, info in index.items():
filepath = os.path.join("poets_data", info["filename"])
with open(filepath, 'r', encoding='utf-8') as pf:
self.poets_data[name] = json.load(pf)
except:
self.poets_list = ["李白", "杜甫"]
self.poets_data = {name: {"name": name} for name in self.poets_list}
def get_today_quote(self):
"""根据日期固定随机种子,同一天返回同一句名句"""
today_str = datetime.now().strftime("%Y-%m-%d")
random.seed(today_str)
if self.daily_quotes:
return random.choice(self.daily_quotes)
return {"quote": "床前明月光,疑是地上霜。", "source": "静夜思", "author": "李白", "dynasty": "唐"}
# ================== 界面构建 ==================
def create_widgets(self):
tk.Label(self.root, text="📜 诗 境 游 📜", font=("楷体", 28, "bold"),
bg='#f0f0f0', fg='#8B4513').pack(pady=10)
self.date_label = tk.Label(self.root, text="", font=("宋体", 10),
bg='#f0f0f0', fg='#666')
self.date_label.pack()
self.update_date()
main_frame = tk.Frame(self.root, bg='#f0f0f0')
main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
# 左侧按钮区
left_canvas = tk.Canvas(main_frame, bg='#e8d8c8', width=200, highlightthickness=0)
left_scrollbar = tk.Scrollbar(main_frame, orient="vertical", command=left_canvas.yview)
left_canvas.configure(yscrollcommand=left_scrollbar.set)
left_canvas.pack(side=tk.LEFT, fill=tk.Y)
left_scrollbar.pack(side=tk.LEFT, fill=tk.Y)
left_frame = tk.Frame(left_canvas, bg='#e8d8c8')
left_canvas.create_window((0, 0), window=left_frame, anchor="nw", width=200)
btn_style = {"font": ("微软雅黑", 11), "fg": "white", "activebackground": "#A0522D",
"cursor": "hand2", "width": 16, "pady": 8}
btn_brown = {**btn_style, "bg": "#8B4513"}
btn_red = {**btn_style, "bg": "#B22222", "activebackground": "#8B0000"}
tk.Button(left_frame, text="📖 古诗词查询", command=self.query_poem, **btn_brown).pack(pady=8, padx=10,
fill=tk.X)
tk.Button(left_frame, text="📝 古诗词赏析", command=self.appreciate_poem, **btn_brown).pack(pady=8, padx=10,
fill=tk.X)
tk.Button(left_frame, text="🌟 每日诗词推荐", command=self.daily_recommend, **btn_brown).pack(pady=8, padx=10,
fill=tk.X)
tk.Button(left_frame, text="🔍 诗海寻珠", command=self.tag_sea, **btn_brown).pack(pady=8, padx=10, fill=tk.X)
tk.Button(left_frame, text="🌺 山花烂漫", command=self.mao_special, **btn_red).pack(pady=8, padx=10, fill=tk.X)
tk.Button(left_frame, text="🚶 诗人漫步", command=self.poet_walk, **btn_brown).pack(pady=8, padx=10, fill=tk.X)
left_frame.update_idletasks()
left_canvas.configure(scrollregion=left_canvas.bbox("all"))
# 右侧区域
right_frame = tk.Frame(main_frame, bg='white', relief=tk.SUNKEN, bd=2)
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
top_bar = tk.Frame(right_frame, bg='white')
top_bar.pack(fill=tk.X, pady=10)
self.back_button = tk.Button(top_bar, text="← 返回", command=self.go_back,
font=("微软雅黑", 10), bg='#cccccc', state='disabled')
self.back_button.pack(side=tk.LEFT, padx=10)
self.func_label = tk.Label(top_bar, text="【 主界面 】", font=("微软雅黑", 16, "bold"),
bg='white', fg='#8B4513')
self.func_label.pack(side=tk.LEFT, expand=True)
# 查询输入框
self.query_frame = tk.Frame(right_frame, bg='white')
tk.Label(self.query_frame, text="请输入诗名:", font=("宋体", 12), bg='white').pack(side=tk.LEFT, padx=5)
self.poem_name_entry = tk.Entry(self.query_frame, font=("宋体", 12), width=25)
self.poem_name_entry.pack(side=tk.LEFT, padx=5)
self.search_btn = tk.Button(self.query_frame, text="查询", command=self.do_search,
bg='#8B4513', fg='white', cursor='hand2')
self.search_btn.pack(side=tk.LEFT, padx=5)
# 留言板输入框
self.note_frame = tk.Frame(right_frame, bg='white')
tk.Label(self.note_frame, text="推荐诗词名:", font=("宋体", 10), bg='white').pack(side=tk.LEFT, padx=5)
self.note_name_entry = tk.Entry(self.note_frame, font=("宋体", 10), width=15)
self.note_name_entry.pack(side=tk.LEFT, padx=5)
tk.Label(self.note_frame, text="推荐理由:", font=("宋体", 10), bg='white').pack(side=tk.LEFT, padx=5)
self.note_reason_entry = tk.Entry(self.note_frame, font=("宋体", 10), width=25)
self.note_reason_entry.pack(side=tk.LEFT, padx=5)
self.submit_note_btn = tk.Button(self.note_frame, text="提交留言", command=self.submit_note,
bg='#8B4513', fg='white', cursor='hand2')
self.submit_note_btn.pack(side=tk.LEFT, padx=5)
# 主内容区(文本)
self.content_area = scrolledtext.ScrolledText(right_frame, wrap=tk.WORD, font=("楷体", 12),
bg='#fef9e6', height=20, width=70)
self.content_area.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# ========== 诗海寻珠(标签墙)==========
self.tag_frame = tk.Frame(right_frame, bg='white')
# 其他容器
self.card_frame = tk.Frame(right_frame, bg='white')
self.card_canvas = None
self.cards_inner_frame = None
self.poet_nav_frame = tk.Frame(right_frame, bg='white')
self.prev_btn = tk.Button(self.poet_nav_frame, text="◀ 上一页", command=self.prev_poet,
font=("微软雅黑", 11), bg='#8B4513', fg='white', padx=15, pady=5)
self.next_btn_poet = tk.Button(self.poet_nav_frame, text="下一页 ▶", command=self.next_poet,
font=("微软雅黑", 11), bg='#8B4513', fg='white', padx=15, pady=5)
self.page_label = tk.Label(self.poet_nav_frame, text="", font=("宋体", 11), bg='white', fg='#8B4513')
self.show_welcome()
self.status_label = tk.Label(self.root, text="✅ V3.0 | 每日名句 + 诗海寻珠全文显示", font=("宋体", 9),
bg='#f0f0f0', fg='#666', anchor='w')
self.status_label.pack(side=tk.BOTTOM, fill=tk.X, padx=20, pady=5)
def update_date(self):
now = datetime.now().strftime("%Y年%m月%d日")
# 显示日期 + 今日名句的出处(简短提示)
quote_source = self.today_quote.get('source', '')
self.date_label.config(text=f"📅 {now} | 🌟 今日名句来自:《{quote_source}》")
# ================== 每日推荐(名句版 + 留言板)==================
def daily_recommend(self):
self.current_mode = "daily"
self.func_label.config(text="【 每日名句推荐 + 留言板 】")
self.hide_all_views()
quote = self.today_quote
content = f"🌟 今日名句\n\n"
content += f"「 {quote.get('quote', '')} 」\n\n"
content += f"—— {quote.get('author', '未知')}({quote.get('dynasty', '')})\n"
content += f" 出自《{quote.get('source', '未知')}》\n\n"
content += "=" * 40 + "\n"
content += "📢 诗友留言推荐\n\n"
if self.recommend_notes:
for note in self.recommend_notes[-8:]:
content += f"《{note['name']}》 —— {note['reason']}\n"
else:
content += "暂无留言,欢迎推荐你喜欢的诗词~\n"
self.content_area.delete('1.0', tk.END)
self.content_area.insert(tk.END, content)
self.note_frame.pack(pady=10)
self.query_frame.pack_forget()
self.back_button.config(state='disabled')
def submit_note(self):
name = self.note_name_entry.get().strip()
reason = self.note_reason_entry.get().strip()
if not name or not reason:
messagebox.showwarning("提示", "请填写诗词名和推荐理由")
return
self.recommend_notes.append({
"name": name,
"reason": reason,
"date": datetime.now().strftime("%Y-%m-%d %H:%M")
})
self.save_recommend_notes()
self.note_name_entry.delete(0, tk.END)
self.note_reason_entry.delete(0, tk.END)
messagebox.showinfo("成功", "感谢推荐!")
self.daily_recommend()
# ================== 诗海寻珠(标签墙)==================
def tag_sea(self):
self.func_label.config(text="【 诗海寻珠 · 标签墙 】")
self.hide_all_views()
self.back_button.config(state='normal')
# 清空标签墙
for w in self.tag_frame.winfo_children():
w.destroy()
self.tag_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
# 标签列表(只保留主题和风格)
tags = [
("🌱 春天", "spring"), ("🍂 秋天", "autumn"), ("👋 离别", "farewell"),
("⚔️ 边塞", "frontier"), ("⛰️ 山水", "landscape"), ("❤️ 爱国", "patriotic"),
("🍷 豪放", "bold"), ("🌸 婉约", "graceful"), ("🧘 禅意", "zen")
]
# 标签-诗词映射
tag_poems = {
"spring": ["春晓", "春望", "鸟鸣涧", "春江花月夜"],
"autumn": ["秋夕", "山居秋暝", "天净沙·秋思", "虞美人·春花秋月何时了"],
"farewell": ["送孟浩然之广陵", "雨霖铃·寒蝉凄切", "别董大", "黄鹤楼"],
"frontier": ["出塞", "使至塞上", "凉州词", "从军行"],
"landscape": ["山居秋暝", "望庐山瀑布", "题西林壁", "江雪", "鹿柴"],
"patriotic": ["春望", "示儿", "破阵子·为陈同甫赋壮词以寄之", "龟虽寿", "白马篇"],
"bold": ["将进酒", "念奴娇·赤壁怀古", "破阵子·为陈同甫赋壮词以寄之",
"白马篇", "沁园春·雪", "沁园春·长沙"],
"graceful": ["雨霖铃·寒蝉凄切", "声声慢·寻寻觅觅", "蝶恋花·庭院深深深几许",
"蝶恋花·槛菊愁烟兰泣露", "青玉案·元夕", "扬州慢·淮左名都"],
"zen": ["鸟鸣涧", "鹿柴", "终南别业", "山居秋暝", "江雪"]
}
# 创建可滚动的标签墙
canvas = tk.Canvas(self.tag_frame, bg='white', highlightthickness=0)
scrollbar = tk.Scrollbar(self.tag_frame, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
inner_frame = tk.Frame(canvas, bg='white')
canvas.create_window((0, 0), window=inner_frame, anchor="nw")
def configure_scroll(e):
canvas.configure(scrollregion=canvas.bbox("all"))
inner_frame.bind("<Configure>", configure_scroll)
def on_mousewheel(e):
canvas.yview_scroll(int(-1 * (e.delta / 120)), "units")
canvas.bind("<MouseWheel>", on_mousewheel)
# 标签样式:3列布局
row_frame = None
for i, (tag_name, tag_key) in enumerate(tags):
if i % 3 == 0:
row_frame = tk.Frame(inner_frame, bg='white')
row_frame.pack(pady=5)
btn = tk.Button(row_frame, text=tag_name,
command=lambda k=tag_key: self.show_tag_poems(k, tag_poems),
font=("微软雅黑", 11, "bold"),
bg='#8B4513', fg='white',
cursor='hand2', padx=15, pady=8, width=12)
btn.pack(side=tk.LEFT, padx=10)
# 初始状态:空白界面
self.content_area.delete('1.0', tk.END)
self.content_area.insert(tk.END, "✨ 点击上方标签,开始诗海寻珠 ✨")
self.switch_to_text_view()
self.tag_inner_frame = inner_frame
self.tag_canvas = canvas
def show_tag_poems(self, tag_key, tag_poems):
poem_names = tag_poems.get(tag_key, [])
if not poem_names:
self.content_area.delete('1.0', tk.END)
self.content_area.insert(tk.END, f"「{tag_key}」暂无推荐诗词,敬请期待~")
self.switch_to_text_view()
return
# 获取标签的中文名
tag_names = {
"spring": "春天", "autumn": "秋天", "farewell": "离别",
"frontier": "边塞", "landscape": "山水", "patriotic": "爱国",
"bold": "豪放", "graceful": "婉约", "zen": "禅意"
}
tag_cn = tag_names.get(tag_key, tag_key)
result = f"🔍 诗海寻珠 · {tag_cn}\n\n"
result += "━" * 40 + "\n\n"
for name in poem_names:
poem = self.poems_db.get(name)
if poem:
result += f"📖 《{name}》\n"
result += f" 作者:{poem['author']}({poem['dynasty']})\n\n"
# 修改:显示全文,不截断
result += f"{poem['content']}\n\n"
result += "━" * 40 + "\n\n"
else:
result += f"📖 《{name}》(暂未收录全文)\n\n"
result += "━" * 40 + "\n\n"
self.content_area.delete('1.0', tk.END)
self.content_area.insert(tk.END, result)
self.switch_to_text_view()
self.back_button.config(state='normal')
self.func_label.config(text=f"【 诗海寻珠 · {tag_cn} 】")
# ================== 查询 / 赏析 ==================
def query_poem(self):
self.current_mode = "query"
self.func_label.config(text="【 古诗词查询 】")
self.show_input_mode("请输入诗名(如:静夜思、将进酒)")
def appreciate_poem(self):
self.current_mode = "appreciate"
self.func_label.config(text="【 古诗词赏析 】")
self.show_input_mode("请输入诗名,将显示赏析与名家点评")
def show_input_mode(self, tip):
self.hide_all_views()
self.query_frame.pack(pady=10)
self.content_area.delete('1.0', tk.END)
self.content_area.insert(tk.END, tip)
self.back_button.config(state='disabled')
def do_search(self):
poem_name = self.poem_name_entry.get().strip()
if not poem_name:
messagebox.showwarning("提示", "请输入诗名")
return
if hasattr(self, 'current_mode') and self.current_mode == "appreciate":
self.show_appreciation(poem_name)
else:
self.show_poem(poem_name)
def show_poem(self, poem_name):
poem = self.poems_db.get(poem_name)
if poem:
text = f"《{poem_name}》\n"
text += f"作者:{poem['author']}({poem['dynasty']})\n\n"
text += poem['content']
self.content_area.delete('1.0', tk.END)
self.content_area.insert(tk.END, text)
self.status_label.config(text=f"✅ 查询成功:《{poem_name}》")
else:
self.content_area.delete('1.0', tk.END)
self.content_area.insert(tk.END, f"❌ 未找到《{poem_name}》")
self.status_label.config(text="❌ 未找到")
def show_appreciation(self, poem_name):
data = self.appreciate_db.get(poem_name)
if data:
text = f"《{poem_name}》 赏析\n\n"
text += "【 赏析 】\n" + data['appreciation'] + "\n\n"
if data.get('comments'):
text += "【 历代名家点评 】\n"
for comment in data['comments']:
text += f"• {comment}\n"
self.content_area.delete('1.0', tk.END)
self.content_area.insert(tk.END, text)
self.status_label.config(text=f"📖 赏析:《{poem_name}》")
else:
self.content_area.delete('1.0', tk.END)
self.content_area.insert(tk.END, f"❌ 暂无《{poem_name}》的赏析数据")
self.status_label.config(text="❌ 暂无赏析")
# ================== 山花烂漫(完整保留)==================
def switch_to_card_view(self):
self.content_area.pack_forget()
self.query_frame.pack_forget()
self.note_frame.pack_forget()
self.tag_frame.pack_forget()
self.poet_nav_frame.pack_forget()
if self.card_frame:
self.card_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
self.create_card_view()
def switch_to_text_view(self):
if self.card_frame:
self.card_frame.pack_forget()
self.content_area.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
def create_card_view(self):
if self.cards_inner_frame:
for w in self.cards_inner_frame.winfo_children():
w.destroy()
else:
self.card_canvas = tk.Canvas(self.card_frame, bg='white', highlightthickness=0)
self.card_scrollbar = tk.Scrollbar(self.card_frame, orient="vertical", command=self.card_canvas.yview)
self.card_canvas.configure(yscrollcommand=self.card_scrollbar.set)
self.card_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.card_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.cards_inner_frame = tk.Frame(self.card_canvas, bg='white')
self.card_canvas.create_window((0, 0), window=self.cards_inner_frame, anchor="nw")
self.cards_inner_frame.bind("<Configure>", self.on_frame_configure)
for title, info in self.mao_poems.items():
self.add_card(title, info)
self.cards_inner_frame.update_idletasks()
self.card_canvas.configure(scrollregion=self.card_canvas.bbox("all"))
self.card_canvas.bind("<MouseWheel>", self.on_mousewheel)
def on_frame_configure(self, e):
self.card_canvas.configure(scrollregion=self.card_canvas.bbox("all"))
def on_mousewheel(self, e):
self.card_canvas.yview_scroll(int(-1 * (e.delta / 120)), "units")
def add_card(self, title, info):
card_container = tk.Frame(self.cards_inner_frame, bg='white', pady=5)
card_container.pack(fill=tk.X, padx=20, pady=5)
card = tk.Frame(card_container, bg='#fef9e6', relief=tk.RAISED, bd=1)
card.pack(fill=tk.X, padx=2, pady=2)
tk.Label(card, text=f"📖 {title}", font=("楷体", 14, "bold"), bg='#fef9e6', fg='#8B4513', anchor='w').pack(
fill=tk.X, padx=15, pady=(10, 5))
tk.Label(card, text=f"作者:{info['author']}", font=("宋体", 10), bg='#fef9e6', fg='#666', anchor='w').pack(
fill=tk.X, padx=15)
preview = info['content'][:50].replace('\n', ' ') + "……"
tk.Label(card, text=preview, font=("宋体", 9), bg='#fef9e6', fg='#888', anchor='w', wraplength=400).pack(
fill=tk.X, padx=15, pady=(0, 5))
tk.Button(card, text="🔍 查看详情", command=lambda t=title: self.show_poem_detail(t),
font=("微软雅黑", 9), bg='#8B4513', fg='white', cursor='hand2', padx=10, pady=2).pack(pady=(0, 10))
def show_poem_detail(self, title):
info = self.mao_poems.get(title)
if not info: return
self.func_label.config(text=f"【 {title} 】")
self.back_button.config(state='normal')
self.switch_to_text_view()
self.query_frame.pack_forget()
self.note_frame.pack_forget()
self.tag_frame.pack_forget()
self.poet_nav_frame.pack_forget()
self.content_area.delete('1.0', tk.END)
self.content_area.insert(tk.END,
f"《{title}》\n作者:{info['author']}\n\n【创作背景】\n{info['background']}\n\n【诗词全文】\n{info['content']}")
self.in_card_view = True
def mao_special(self):
self.func_label.config(text="【 山花烂漫 · 诗词卡片 】")
self.hide_all_views()
self.back_button.config(state='disabled')
self.in_card_view = False
self.switch_to_card_view()
# ================== 诗人漫步 ==================
def poet_walk(self):
if not self.poets_list:
messagebox.showerror("错误", "暂无诗人数据")
return
self.func_label.config(text="【 诗人漫步 · 翻页书 】")
self.hide_all_views()
self.poet_nav_frame.pack(pady=10)
self.current_poet_index = 0
self.show_current_poet()
def show_current_poet(self):
if not self.poets_list: return
name = self.poets_list[self.current_poet_index]
poet = self.poets_data.get(name, {})
self.page_label.config(text=f"{self.current_poet_index + 1}/{len(self.poets_list)}")
self.prev_btn.pack(side=tk.LEFT, padx=10)
self.page_label.pack(side=tk.LEFT, padx=20)
self.next_btn_poet.pack(side=tk.LEFT, padx=10)
works = "\n".join(f" • {w}" for w in poet.get('representative_works', [])) or " 暂无"
text = f"""
【 {poet.get('name', name)} 】
朝代 {poet.get('dynasty', '未知')}
称号 {poet.get('title', '无')}
生卒 {poet.get('life_years', '不详')}
风格 {poet.get('style', '—')}
📖 代表作
{works}
🎭 生平与成就
{poet.get('bio', '暂无')}
✨ 传世名句
「 {poet.get('famous_line', '——')} 」
"""
self.content_area.delete('1.0', tk.END)
self.content_area.insert(tk.END, text)
self.switch_to_text_view()
def prev_poet(self):
if self.current_poet_index > 0:
self.current_poet_index -= 1
self.show_current_poet()
else:
messagebox.showinfo("书签", "已经是第一位诗人")
def next_poet(self):
if self.current_poet_index < len(self.poets_list) - 1:
self.current_poet_index += 1
self.show_current_poet()
else:
messagebox.showinfo("书签", "已经是最后一位诗人")
# ================== 辅助函数 ==================
def go_back(self):
if self.in_card_view:
self.mao_special()
else:
self.show_welcome()
def hide_all_views(self):
self.card_frame.pack_forget()
self.poet_nav_frame.pack_forget()
self.query_frame.pack_forget()
self.note_frame.pack_forget()
self.tag_frame.pack_forget()
self.content_area.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
def show_welcome(self):
self.func_label.config(text="【 主界面 】")
self.hide_all_views()
self.back_button.config(state='disabled')
self.content_area.delete('1.0', tk.END)
welcome = "欢迎使用《诗境游》 V3.0\n\n"
welcome += "📖 古诗词查询\n"
welcome += "📝 古诗词赏析\n"
welcome += "🌟 每日名句推荐 + 留言板\n"
welcome += "🔍 诗海寻珠 · 标签墙(全文显示)\n"
welcome += "🌺 山花烂漫\n"
welcome += "🚶 诗人漫步"
self.content_area.insert(tk.END, welcome)
def run(self):
self.root.mainloop()
if __name__ == "__main__":
game = PoetryGame()
game.run()
3. 实验过程中遇到的问题和解决过程
- 问题1:在我的最初的构想中,这个小程序还需要包括古诗词小游戏功能,比如飞花令、诗词填空,但是经过DeepSeek好几轮生成,游戏模块都无法正常使用;
- 问题1解决方案:由于这个模块是我放在实验的最后一步做的,而且所占代码量极大,故推断,玩不了小游戏的原因是该部分代码极易与先前已有的模块代码互相干扰,导致程序不稳定。在这一判断的基础上,我取消了游戏模块,把它替换成了“诗海寻珠”模块,推出按主题风格浏览诗词的新功能。
- 问题2:在完成诗词查询模块时,创建JSON文件后,虽然都把格式后缀改成了“.json”,但是代码无法读取文件,无法查询到相关诗歌内容;
- 问题2解决方案:经过排查,发现是文件名本身出错了,我把“poems_db.json”打成了“poem_db.json”,少加了一个s,加上之后,就可以顺利地输入诗名,然后查询到诗歌原文了。
4.总结与感想
1.知识点总结
- Python的定义
Python 是一种解释型、高级、面向对象的通用编程语言,具有动态类型系统。 - Python的语法
特点:a.注释规则 b.代码缩进、编码规范
包括:a.保留字、标识符、变量
b.基本数据类型:数字类型、字符串类型、布尔类型、数据类型转换
c.运算符:算术运算符、赋值运算符、比较运算符、逻辑运算符、位运算符
d.输入与输出 - 流程控制语句
a.程序结构:顺序结构、分支结构、循环结构
选择语句:if、else、elif
b.循环语句:while、for、range/break、continue
c.条件表达式:max = a if a>b else b
d.空语句:pass - 序列的运用
列表(list)、元组(tuplel)、字典(dictionary)、集合(set)
-字符串
字符串:a.拼接+重复字符串 b.截断:同序列 c.分割与合并字符串 d.检索字符串 e.大小写:lower()、upper()方法 f.去掉字符串首尾字符:strip()、lstrip()、rstrip() g.格式化字符串
正则表达式:普通字符、特殊字符、限定符、查找 - 函数
传递、实参、形参 - 面向对象
面向对象三要素:封装+继承+多态
类=属性(变量)+方法(函数) - 模块与异常处理
- 文件操作与数据库
- 网络爬虫
- socket技术(套接字)
2.课程感想
在知道这一学期我们要学习Python时,其实我一开始很忐忑不安,因为作为文科生,我对如何写代码可以算得上是一窍不通,而且我也对编程这种复杂的东西几乎有一种天然的恐惧感与敬畏感。但是感谢王老师手把手教我们如何安装PyCHarm,如何打包代码,如何编写不同的代码,而且最感动的是,王老师用一种幽默生动的方式为我们呈现出知识点,既有效地抵消了我对编程的畏怯,也让我学到了真东西。可以说,Python丰富了我的生活,让很多从前只存在于我脑海中的构想变得触手可及(例如本次实验中的古诗词小程序),也为我打开了另一扇通往技术世界的大门。我慢慢领悟到了学好一门技术,对于我们以后的发展也益处多多。最后,再次感谢王老师在我遇到技术难题时耐心解答我的疑惑,也祝王老师工作顺利,天天开心!
3.小小建议
在手把手敲代码的时候,王老师敲得有点太快了,有些反应不过来,希望老师给学弟学妹讲课的时候可以稍稍慢一点,让大家都可以跟上老师的节奏。
浙公网安备 33010602011771号