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

Python GUI中Listbox无法显示课程数据问题排查与解决

问题修复:Tkinter时间表工具CSV读取后Listbox无内容显示

排查出的核心问题

  • display_courses函数参数设计错误:默认参数all_courses=None,调用时未正确传递全局变量,导致过滤函数接收空值无法生成有效结果
  • read_csv调用display_courses时未传入全局all_courses变量,且未清空全局列表,多次读取会重复累加数据
  • add_course/remove_course等函数的timetable参数默认值为None,调用时未传入实际列表,会触发AttributeError
  • Listbox直接插入原始列表对象,需转换为字符串才能正常显示
  • display_warning函数逻辑混乱,错误修改按钮绑定命令,未实现有效的路径检查

修复后的完整代码

import tkinter as tk
import csv
from tkinter import messagebox
from tkinter import ttk

# 全局变量初始化
all_courses = []
timetable = []


def read_csv(path):
    # 清空全局课程列表,避免重复读取
    all_courses.clear()
    try:
        with open(path, newline='', encoding='utf-8') as csvfile:
            data = csv.reader(csvfile)
            all_courses.extend([row for row in data])
        # 读取成功后直接显示课程
        display_courses()
    except FileNotFoundError:
        messagebox.showerror("错误", "指定的文件路径不存在")
    except Exception as e:
        messagebox.showerror("错误", f"读取文件失败:{str(e)}")


def filter_courses(year, code):
    # 直接使用全局all_courses进行过滤
    filtered_courses = []
    for course in all_courses:
        # 确保课程数据有足够的列,避免索引越界
        if len(course) >= 2:
            year_match = (year in course[1] or year == "")
            code_match = (code in course[0] or code == "")
            if year_match and code_match:
                filtered_courses.append(course)
    return filtered_courses


def add_course():
    try:
        selected = courses_list.get(courses_list.curselection())
        # 转换回列表格式(因为Listbox显示的是字符串)
        course = selected.split(", ")
        if course not in timetable:
            timetable.append(course)
            selected_courses_list.insert(tk.END, selected)
            print("Added course:", course)
        else:
            messagebox.showinfo("提示", "该课程已在时间表中")
    except tk.TclError:
        messagebox.showwarning("提示", "请先选择要添加的课程")


def remove_course():
    try:
        selected_idx = selected_courses_list.curselection()[0]
        selected = selected_courses_list.get(selected_idx)
        course = selected.split(", ")
        timetable.remove(course)
        selected_courses_list.delete(selected_idx)
        print("Removed course:", course)
    except (tk.TclError, ValueError):
        messagebox.showwarning("提示", "请先选择要移除的课程")


def clear_timetable():
    timetable.clear()
    selected_courses_list.delete(0, tk.END)
    print("Timetable cleared.")


def save_timetable():
    if not timetable:
        messagebox.showwarning("提示", "时间表为空,无需保存")
        return
    try:
        with open("timetable.csv", "w", newline='', encoding='utf-8') as f:
            writer = csv.writer(f)
            writer.writerows(timetable)
        messagebox.showinfo("成功", "时间表已保存")
        print("Timetable saved.")
    except Exception as e:
        messagebox.showerror("错误", f"保存失败:{str(e)}")


def display_courses():
    # 检查是否已读取课程数据
    if not all_courses:
        messagebox.showwarning("提示", "请先读取CSV文件")
        return
    filtered_courses = filter_courses(year_var.get(), code_var.get())
    courses_list.delete(0, tk.END)
    for course in filtered_courses:
        # 将列表转换为字符串后插入Listbox
        courses_list.insert(tk.END, ", ".join(course))


# 创建GUI窗口
root = tk.Tk()
root.title("时间表制作工具")

# 文件路径输入区域
file_path_label = tk.Label(root, text="CSV文件路径:")
file_path_label.pack(pady=2)
file_path_entry = tk.Entry(root, width=50)
file_path_entry.pack(pady=2)

# 功能按钮区域
read_button = tk.Button(root, text="读取文件", command=lambda: read_csv(file_path_entry.get()))
read_button.pack(pady=2)

display_button = tk.Button(root, text="显示课程", command=display_courses)
display_button.pack(pady=2)

# 过滤选项区域
year_label = tk.Label(root, text="年级筛选:")
year_label.pack(pady=2)
year_var = tk.StringVar()
year_var.set("")
year_dropdown = tk.OptionMenu(root, year_var, "1", "2", "3", "4", "5")
year_dropdown.pack(pady=2)

code_label = tk.Label(root, text="学科代码筛选:")
code_label.pack(pady=2)
code_var = tk.StringVar()
code_var.set("")
code_dropdown = tk.OptionMenu(root, code_var, "CHI", "CS", "ECE", "ECON", "EE", "EECS", "ENGR", "FRE", "IE", "ISE", "LIFE",
                              "MATH", "MGT", "UNI")
code_dropdown.pack(pady=2)

# 课程列表区域
courses_label = tk.Label(root, text="可选课程:")
courses_label.pack(pady=2)
courses_list = tk.Listbox(root, width=80, height=10)
courses_list.pack(pady=2)

# 已选课程区域
selected_courses_label = tk.Label(root, text="已选课程(时间表):")
selected_courses_label.pack(pady=2)
selected_courses_list = tk.Listbox(root, width=80, height=10)
selected_courses_list.pack(pady=2)

# 时间表操作按钮区域
add_button = tk.Button(root, text="添加到时间表", command=add_course)
add_button.pack(side=tk.LEFT, padx=10, pady=5)
remove_button = tk.Button(root, text="从时间表移除", command=remove_course)
remove_button.pack(side=tk.LEFT, padx=10, pady=5)
clear_button = tk.Button(root, text="清空时间表", command=clear_timetable)
clear_button.pack(side=tk.LEFT, padx=10, pady=5)
save_button = tk.Button(root, text="保存时间表", command=save_timetable)
save_button.pack(side=tk.LEFT, padx=10, pady=5)

# 样式设置
s = ttk.Style()
s.theme_use("clam")
courses_list.configure(background='yellow')
selected_courses_list.configure(background='lightblue')

root.mainloop()

关键修复说明

  1. 全局变量优化:新增全局timetable列表,避免函数参数默认值为None导致的报错
  2. 函数参数调整:filter_courses直接使用全局all_courses,display_courses不再需要传递参数,避免空值问题
  3. 数据显示修复:将CSV读取的列表数据转换为字符串后插入Listbox,确保正常显示
  4. 错误处理增强:添加文件读取、课程选择等场景的异常捕获,弹出提示信息
  5. 逻辑修正:修复read_csv的重复数据问题,优化数据检查逻辑,改为在display_courses中验证是否已读取数据
  6. 用户体验优化:调整布局间距,修改按钮文字更符合中文习惯,添加操作成功/失败提示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 08:25:27