You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于SQLite3与CustomTkinter的读书记录桌面应用:笔记查看按钮实现方案咨询

解决方案

我来帮你搞定这个需求!要实现同一行显示笔记按钮(无笔记时隐藏),并且点击按钮弹出窗口查看长笔记,我们需要做几个关键改动,下面一步步来:

1. 新增查看笔记的弹窗函数

首先要写一个函数,用来弹出新窗口显示笔记内容。我们把它放在MyFrame类里,和书籍列表逻辑关联更紧密。

2. 修改书籍列表渲染逻辑

在view方法里遍历每本书时,检查prise_de_note字段是否有有效内容:

  • 如果有非空笔记,就创建按钮和书名标签放在同一行(不同列)
  • 如果没有笔记,就不渲染这个按钮

3. 添加列表自动刷新功能

现在添加新书后列表不会自动更新,所以我们要在添加完成后调用刷新方法,同时先清空旧控件避免重复渲染。

修改后的完整代码

import os
import sqlite3
import customtkinter as ctk

dossier_actuel = os.path.dirname(os.path.abspath(__file__))
chemin_base_donnees = os.path.join(dossier_actuel, "bibliotheque.db")

def connection():
    return sqlite3.connect(chemin_base_donnees)

def crea_biblio():
    try:
        with connection() as conn:
            cursor = conn.cursor()
            sql = '''CREATE TABLE IF NOT EXISTS Livres (
                    id_livre INTEGER PRIMARY KEY AUTOINCREMENT,
                    titre_livre TEXT,
                    auteur_livre TEXT,
                    prise_de_note TEXT
                    );'''
            cursor.execute(sql)
            conn.commit()
    except Exception as e:
        print(f"An error occured while creating the table : {e}")

# 初始化数据库表
crea_biblio()

class MyFrame(ctk.CTkScrollableFrame):
    def __init__(self, master, **kwargs):
        super().__init__(master, **kwargs)
        self.view()
    
    def open_note_window(self, note_content):
        """弹出窗口显示笔记内容"""
        note_window = ctk.CTkToplevel(self)
        note_window.title("笔记详情")
        note_window.geometry("400x300")
        
        # 用文本框显示长笔记,设置为只读防止误改
        note_text = ctk.CTkTextbox(note_window, wrap="word")
        note_text.pack(padx=15, pady=15, fill="both", expand=True)
        note_text.insert("1.0", note_content)
        note_text.configure(state="disabled")
    
    def view(self):
        # 先清空旧控件,避免重复渲染
        for widget in self.winfo_children():
            widget.destroy()
            
        try:
            with connection() as conn:
                cursor = conn.cursor()
                cursor.execute("SELECT titre_livre, auteur_livre, prise_de_note FROM Livres ORDER BY id_livre")
                lignes = cursor.fetchall()
                
                for i, ligne in enumerate(lignes):
                    titre, auteur, note = ligne
                    # 书名作者标签
                    label = ctk.CTkLabel(self, text=f"{titre} écrit par {auteur}")
                    label.grid(row=i, column=1, padx=20, pady=20, sticky="w")
                    
                    # 只有笔记非空时才显示按钮
                    if note and note.strip():
                        view_btn = ctk.CTkButton(
                            self, 
                            text="查看笔记", 
                            command=lambda n=note: self.open_note_window(n),
                            width=80
                        )
                        view_btn.grid(row=i, column=2, padx=10, pady=20)
                        
        except Exception as e:
            print(f'An error occured while loading books : {e}')

class App(ctk.CTk):
    def __init__(self):
        super().__init__()
        self.geometry("700x500")  # 加宽窗口给按钮腾空间
        self.title("我的书籍库")
        
        # 左侧输入区域
        self.entry = ctk.CTkEntry(self, placeholder_text="Titre du livre")
        self.entry.grid(row=0, column=0, padx=20, pady=10)
        
        self.entry2 = ctk.CTkEntry(self, placeholder_text="Auteur")
        self.entry2.grid(row=1, column=0, padx=20, pady=10)
        
        self.button = ctk.CTkButton(self, text="Ajouter le livre", command=self.button_click)
        self.button.grid(row=2, column=0, padx=20, pady=10)
        
        # 右侧书籍列表区域
        self.my_frame = MyFrame(master=self, width=400, height=400)
        self.my_frame.grid(row=0, column=1, rowspan=3, padx=20, pady=20, sticky="nsew")
        
        # 布局权重设置,让列表框可以自适应窗口拉伸
        self.grid_columnconfigure(1, weight=1)
        self.grid_rowconfigure(0, weight=1)
    
    def button_click(self):
        titre = self.entry.get().strip()
        auteur = self.entry2.get().strip()
        
        if not titre or not auteur:
            print("请输入完整的书名和作者!")
            return
            
        try:
            with connection() as conn:
                cursor = conn.cursor()
                sql = "INSERT INTO Livres (titre_livre, auteur_livre) VALUES (?, ?);"
                cursor.execute(sql, (titre, auteur))
                conn.commit()
                print("书籍添加成功!")
        except Exception as e:
            print(f"An error occurred while inserting the book: {e}")
        
        # 清空输入框并刷新书籍列表
        self.entry.delete(0, "end")
        self.entry2.delete(0, "end")
        self.my_frame.view()

if __name__ == "__main__":
    app = App()
    app.mainloop()

关键改动说明

  • open_note_window方法:创建顶层弹窗,用CTkTextbox适配长文本显示,设置只读模式防止误编辑。
  • 按钮显示逻辑:通过note.strip()判断笔记是否为有效内容,避免空字符串或空格导致按钮误显示;用lambda传递当前书籍的笔记内容给弹窗函数。
  • 列表刷新:在view方法开头销毁所有旧控件,添加新书后调用self.my_frame.view()实现自动刷新。
  • 布局优化:加宽主窗口、调整grid的sticky属性和权重,让列表区域可以自适应窗口大小变化。

这样就完全实现了你要的功能:有笔记的书籍条目同一行显示按钮,点击弹出窗口查看长笔记,无笔记时按钮自动隐藏,而且添加新书后列表会实时更新。

内容的提问来源于stack exchange,提问作者Hugo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 10:47:34