做个课程表吧
文章目錄
- 抽象
- 顯示效果
- 管理課程
- 實(shí)現(xiàn)課程表
- 導(dǎo)入必要包
- 導(dǎo)入數(shù)據(jù)
- 時間初始化
- 繪制課程表的核心
- 創(chuàng)建主窗體
- 繪制課程小格子
- 其他功能
- 上下周
- 跳轉(zhuǎn)周
- 管理課程
- 設(shè)置周
- 轉(zhuǎn)換數(shù)據(jù)
抽象
首先,我們需要明確自己的設(shè)計需求。
課程表應(yīng)該能讀取課程,顯示課程,管理課程。
顯示效果
首先,我們顯示的應(yīng)該是本周的課程,課程信息應(yīng)該包括 課程名、節(jié)、地點(diǎn)、時間等必要信息,不同課程最好有不同顏色區(qū)分,同種課程的顏色最好相同。如下:
| 第一節(jié) | 課程一 | 課程二 | …… |
| 第二節(jié) | 課程三 | 課程四 | …… |
| …… | …… | …… | …… |
另外,我們有時候需要查看上下周的課程,所以應(yīng)該有一個切換周次的按鈕。
管理課程
我們需要根據(jù)當(dāng)前是第幾周來顯示課程,所以需要保存第一周的時間;同時,也要顯示當(dāng)前是第幾周的課程數(shù)據(jù),所以需要保存每一節(jié)課的時間。
我們需要添加課程、刪除課程,必要時能夠修改課程。
另外,有時不想手動輸入課程數(shù)據(jù),我們應(yīng)該能夠直接從教務(wù)系統(tǒng)導(dǎo)入課程,需要一系列的鍵值對。
因此,我們的需要一個啟動文件data.json:
{"start": [2020, 2, 20],"local": ["kbList"], "book": {"name": "kcmc","teacher": "xm","week": "zcd", "part": "jcor","weekday": "xqjmc","address": "cdmc"}, "time": {"1": "8:50","2": "9:40", "3": "10:40", "4": "11:30", "5": "14:00", "6": "14:50", "7": "15:45", "8": "16:35","9": "19:00", "10": "19:55", "11": "20:50", "12": "21:45"} }接下來是保存課程的數(shù)據(jù):
{"課程名": {"color": "#665A79", "subject": [{"teacher": "教師", "week": "1-16周(雙)", "weekday": "星期幾", "address": "地點(diǎn)", "part": "3-4"}]}}json不支持中文,打開后會有很多轉(zhuǎn)義符。
實(shí)現(xiàn)課程表
導(dǎo)入必要包
根據(jù)上面需求,我們能夠顯示時間的datetime包,讀取數(shù)據(jù)的json包,繪制界面的tkinter包,判斷文件是否存在的os包,還要一個隨機(jī)數(shù)來隨機(jī)生成顏色。
import datetime import json import tkinter import os.path from random import randint導(dǎo)入數(shù)據(jù)
首先我們要判斷啟動文件是否存在,如果不存在就生成一個啟動文件。
if os.path.isfile("data.json"):# 用外部文件來保存鍵值對with open("data.json", "r") as f:init = json.loads(f.read()) else:with open("data.json", "w") as f:init = {"start": [2020, 2, 20],"time":{"1": "8:50","2": "9:40","3": "10:40","4": "11:30","5": "14:00","6": "14:50","7": "15:45","8": "16:35","9": "19:00","10": "19:55","11": "20:50","12": "21:45"}}json.dump(init, f)啟動文件存在后,用就開始讀取課程數(shù)據(jù)。如果課程數(shù)據(jù)文件不存在,則創(chuàng)建。
# 刷新 def flesh():global js, weeksif os.path.isfile("my_class.json"):# 保存課程數(shù)據(jù)with open("my_class.json", "rb") as f:class_js = f.read()js = json.loads(class_js) # 轉(zhuǎn)化為jsonelse:with open("my_class.json", "w") as f:f.write("{}")js = {}read_class(weeks)時間初始化
我們要判斷當(dāng)前是第幾周。
首先,我們要知道第一周在什么時候。我們把第一周的時間保存在啟動文件的start上面,第一周的開始應(yīng)該是星期天,如果不是星期天,就更改到星期天。
然后,我們要算出今天離第一周差了幾天,根據(jù)天數(shù)計算出當(dāng)前是第幾周,保存到week上。
另外,還需要判斷今天是星期幾,保存在now_week上
def time_init():global weeks, now_week# 確認(rèn)開始的日期 年/月/日init_year = init["start"][0]init_mouth = init["start"][1]init_day = init["start"][2]# 如果開始的一天不是周日,則將開始的日期變?yōu)橹苋?/span>if not datetime.datetime(init_year, init_mouth, init_day).strftime("%w") == 0:init_day -= eval(datetime.datetime(init_year, init_mouth, init_day).strftime("%w"))# 初始化的時間init_date = datetime.datetime(init_year, init_mouth, init_day)# 現(xiàn)在的時間now_date = datetime.datetime.today()# 間隔的天數(shù)days = (now_date - init_date).days# 間隔的周數(shù),第一周為1weeks = int(days / 7) + 1# 框出今天星期幾now_week = eval(now_date.strftime("%w"))time_init()weekday = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]繪制課程表的核心
創(chuàng)建主窗體
創(chuàng)建一個窗體,窗體由幾部分構(gòu)成,分別是課程表的框架還有一些功能的按鈕。
top = tkinter.Tk() # 創(chuàng)建一個窗體 top.geometry("1100x650+200+50") # 改變窗體的大小 top.title('課程表') top.resizable(0, 0)# 框架 box = tkinter.LabelFrame(top, text="課程表", background="#F8F8FF", height=600, width=1100) box.pack()set = tkinter.LabelFrame(top, text="管理", height=100, width=1100) set.pack()label_now_week = tkinter.Label(set, text="現(xiàn)在是第{}周,當(dāng)前的周數(shù)為".format(weeks)) label_now_week.pack(side=tkinter.LEFT)week = tkinter.Variable() week.set(weeks)entry = tkinter.Entry(set, textvariable=week, width=10) entry.pack(side=tkinter.LEFT)last = tkinter.Button(set, text="跳轉(zhuǎn)", command=jump) last.pack(side=tkinter.LEFT)# 上下周按鈕 last = tkinter.Button(set, text="上一周", command=last_week) next = tkinter.Button(set, text="下一周", command=next_week) last.pack(side=tkinter.LEFT) next.pack(side=tkinter.LEFT)# 數(shù)據(jù)控制按鈕 chang_button = tkinter.Button(set, text="導(dǎo)入數(shù)據(jù)", command=data_change) chang_button.pack(side=tkinter.LEFT)# 數(shù)據(jù)控制按鈕 command_button = tkinter.Button(set, text="管理課程", command=command) command_button.pack(side=tkinter.LEFT)# 刷新 time_button = tkinter.Button(set, text="管理起始周-上課時間", command=set_time) time_button.pack(side=tkinter.LEFT)# 刷新 flesh_button = tkinter.Button(set, text="刷新", command=flesh) flesh_button.pack(side=tkinter.LEFT)# 關(guān)于 about_button = tkinter.Button(set, text="關(guān)于", command=about) about_button.pack(side=tkinter.LEFT)實(shí)現(xiàn)的效果如下:
繪制課程小格子
接下來讓我們顯示,這個功能是根據(jù)當(dāng)前是第幾周來顯示課程,如果是現(xiàn)在周就顯示現(xiàn)在的課程,如果是點(diǎn)了上一周下一周就顯示該周課程。
這個函數(shù)主要用于判斷課程是否是當(dāng)前周的課程。
在點(diǎn)擊上一周下一周后,該函數(shù)會被用到,所以要先刪去課程表上之前周的課程。
如果課程是單周課程(數(shù)據(jù)包含單字),需要判斷現(xiàn)在是否是單周,雙周同理。
def read_class(_week):for widget in box.winfo_children():widget.destroy()draw_week()for c in js:name = cfor i in js[c]['subject']:_week = i["week"]# 判斷課程是否是單雙周的課程if "單" in _week:_week = _week.replace("周(單)", "")_week = _week.split("-")# 開始周/結(jié)束周start_week, end_week = eval(_week[0]), eval(_week[-1])if weeks % 2 == 1: # 判斷是否是單周if start_week <= weeks <= end_week: # 判斷該課程是否是當(dāng)前周的課程if start_week <= weeks <= end_week: # 判斷該課程是否是當(dāng)前周的課程# 根據(jù)節(jié)來優(yōu)化顯示效果draw_box(name, i)elif "雙" in _week:_week = _week.replace("周(雙)", "")_week = _week.split("-")# 開始周/結(jié)束周start_week, end_week = eval(_week[0]), eval(_week[-1])if weeks % 2 == 0: # 判斷是否是雙周if start_week <= weeks <= end_week: # 判斷該課程是否是當(dāng)前周的課程if start_week <= weeks <= end_week: # 判斷該課程是否是當(dāng)前周的課程draw_box(name, i)else:_week = _week.replace("周", "")_week = _week.split("-")# 開始周/結(jié)束周start_week, end_week = eval(_week[0]), eval(_week[-1])if start_week <= weeks <= end_week: # 判斷該課程是否是當(dāng)前周的課程# 根據(jù)節(jié)來優(yōu)化顯示效果draw_box(name, i)如果確實(shí)是單周課程,就進(jìn)行繪制。
def draw_box(courses, course):scr = "{}\n講師 {}\n周 {}\n地點(diǎn) {}".format(courses, course["teacher"], course["week"], course["address"]) # 要顯示的課程信息part = course["part"]part = part.split("-")start_part, end_part = eval(part[0]), eval(part[-1])# 確認(rèn)文本的位置x = weekday.index(course["weekday"])# 創(chuàng)建一個文本控件text = tkinter.Label(box, text=scr, width=20, fg="#FFFFFF", bg=js[courses]['color'],height=2 * (end_part - start_part + 1))text.place(x=x * 150 + 40, y=start_part * 40 + 20) # 在屏幕上放置文本控件繪制效果如下:
其他功能
上下周
兩個函數(shù)用于顯示上下周,與兩個按鈕綁定。
上一周時,如果周數(shù)為1,就禁止上一周的按鈕操作。
def next_week():global weeksweeks += 1read_class(weeks)week.set(weeks)def last_week():global weeksif weeks > 1:weeks -= 1read_class(weeks)week.set(weeks)跳轉(zhuǎn)周
上下周按了太多了?直接輸入數(shù)字快速跳轉(zhuǎn)周吧。
需要判斷輸入的是否是數(shù)字,如果不是數(shù)字就判斷為無效輸入。
# 跳轉(zhuǎn) def jump():global weeksif entry.get().isnumeric():weeks = eval(entry.get())read_class(weeks)week.set(weeks)else:week.set(weeks)## 得到一個彩色
tkinter用的是兩位十六進(jìn)制保存紅、綠、藍(lán)顏色的數(shù)據(jù)。不同數(shù)值混合得到的顏色不同。結(jié)果前面需要加個“#”。我們只取中間色,在5到B之間取。最后返回一個類似“#AAAAAA”的數(shù)據(jù)。
def get_a_color():# 多彩效果text = "56789AB"color = "#"for i in range(6):index = randint(0, len(text) - 1)color = color + text[index]return color管理課程
我們對課程數(shù)據(jù)的管理有獲取、增加、刪除、保存的操作。
用列表保存課程名,如果獲取之后可以修改。
增加課程時,隨機(jī)獲取一種顏色,保存到數(shù)據(jù)中。
上面兩個,都需要用戶按下保存時才進(jìn)行保存。
刪除時,直接刪除課程。
# 管理課程 def command():def get_info():data = js[list.get(tkinter.ACTIVE)]subjects = data["subject"]data_information.delete(0.0, tkinter.END)data_information.insert(0.0, "{} {}\n".format(list.get(tkinter.ACTIVE), data["color"]))for subject in subjects:if len(subject["teacher"]) > 7:teacher = subject["teacher"][0:7] + "等"else:teacher = subject["teacher"]scr = "{} {} {} {} {}\n". \format(teacher, subject["week"], subject["weekday"], subject["address"], subject["part"])data_information.insert(tkinter.INSERT, scr)def new():data_information.delete(0.0, tkinter.END)data_information.insert(0.0, "課程名 {}\n教師 1-20周(單) 星期一 地點(diǎn) 1-12".format(get_a_color()))def save():scr = data_information.get(0.0, tkinter.END)scr = scr.split("\n")name = scr[0]subject = []for i in scr[1:-1]:if i == "":passelse:i = i.split(" ")subject.append({"teacher": i[0], "week": i[1], "weekday": i[2], "address": i[3], "part": i[4]})class_key = scr[0].split(" ")js[class_key[0]] = {"color": class_key[1], "subject": subject}with open("my_class.json", "w") as f:json.dump(js, f)myself_flesh()def delete():js.pop(list.get(tkinter.ACTIVE))with open("my_class.json", "w") as f:json.dump(js, f)myself_flesh()def myself_flesh():list.delete(0, tkinter.END)n = 0for i in js:list.insert(n, i)n += 1list.pack(side=tkinter.LEFT)command_win = tkinter.Tk() # 創(chuàng)建一個窗體command_win.geometry("500x200+200+50") # 改變窗體的大小command_win.title('管理數(shù)據(jù)')command_win.resizable(0, 0)list = tkinter.Listbox(command_win)n = 0for i in js:list.insert(n, i)n += 1list.pack(side=tkinter.LEFT)data_frame = tkinter.LabelFrame(command_win, text="數(shù)據(jù)詳情")data_frame.pack(side=tkinter.LEFT)button_frame = tkinter.Frame(data_frame)button_get = tkinter.Button(button_frame, text="獲取", command=get_info)button_get.pack(side=tkinter.LEFT)button_new = tkinter.Button(button_frame, text="新增", command=new)button_new.pack(side=tkinter.LEFT)button_save = tkinter.Button(button_frame, text="保存", command=save)button_save.pack(side=tkinter.LEFT)button_del = tkinter.Button(button_frame, text="刪除", command=delete)button_del.pack(side=tkinter.LEFT)button_frame.pack()data_information = tkinter.Text(data_frame)data_information.pack()實(shí)現(xiàn)的效果如下:
設(shè)置周
用戶可以直接輸入起始周,也可以更改時間。
def set_time():def save():# 判斷是否有效日期try:datetime.datetime.strptime(start_time.get(), "%Y-%m-%d")split_time = start_time.get().split("-")split_time = [eval(split_time[0]), eval(split_time[1]), eval(split_time[2])]init["start"] = split_timeexcept Exception:start_time.delete(0, tkinter.END)start_time.insert(0, "{}-{}-{}".format(init_year, init_mouth, init_day))# 修改課程時間part = text.get(0.0, tkinter.END).split("\n")dic = {}n = 0for little_part in part:if little_part == "":passelse:n += 1dic[str(n)] = little_partinit["time"] = dic# 保存數(shù)據(jù)with open("data.json", "w") as f:json.dump(init, f)set_time_win = tkinter.Tk() # 創(chuàng)建一個窗體set_time_win.geometry("250x200+200+50") # 改變窗體的大小set_time_win.title('關(guān)于軟件')set_time_win.resizable(0, 0)init_year = init["start"][0]init_mouth = init["start"][1]init_day = init["start"][2]frame = tkinter.Frame(set_time_win)frame.pack()label = tkinter.Label(frame, text="起始周的時間")label.pack(side=tkinter.LEFT)start_time = tkinter.Entry(frame)start_time.insert(0, "{}-{}-{}".format(init_year, init_mouth, init_day))start_time.pack()times = tkinter.LabelFrame(set_time_win, text="每節(jié)課的時間")times.pack(side=tkinter.LEFT)text = tkinter.Text(times, width=25, height=10)dic = init["time"]for i in dic:text.insert(tkinter.END, dic[i] + "\n")text.pack()print(dic)button_save = tkinter.Button(set_time_win, text="保存", command=save)button_save.pack(side=tkinter.RIGHT)實(shí)現(xiàn)的效果如下:
轉(zhuǎn)換數(shù)據(jù)
參照我的上一篇博客,從教務(wù)處導(dǎo)入數(shù)據(jù),并把轉(zhuǎn)換的結(jié)果顯示在窗口的右邊。
# 改變 def data_change():change_win = tkinter.Tk() # 創(chuàng)建一個窗體change_win.geometry("500x265+200+50") # 改變窗體的大小change_win.title('導(dǎo)入數(shù)據(jù)')change_win.resizable(0, 0)data_change.origin = tkinter.Text(change_win, height=20, width=30)data_change.origin.pack(side=tkinter.LEFT)frame_button = tkinter.Frame(change_win, height=300, width=100)frame_button.pack(side=tkinter.LEFT)data_change.translate = tkinter.Text(change_win, height=20, width=30)data_change.translate.pack(side=tkinter.LEFT)button_translate = tkinter.Button(frame_button, text="轉(zhuǎn)換并保存", command=write)button_translate.pack(side=tkinter.TOP)change_win.mainloop()然后要寫入數(shù)據(jù),
def write():key = init["book"]text = json.loads(data_change.origin.get(0.0, tkinter.END)) # 轉(zhuǎn)化為jsondata = {}# 抽象化讀取字典for i in init["local"]:text = text[i]for course in text:class_data = {}print(course[key["name"]])if course[key["name"]] in data:subject = data[course[key["name"]]]["subject"]print(course[key["name"]])else:subject = []subject.append({"teacher": course[key["teacher"]], "week": course[key["week"]],"weekday": course[key["weekday"]],"address": course[key["address"]], "part": course[key["part"]]})class_data["color"] = get_a_color()class_data["subject"] = subjectdata[course[key["name"]]] = class_datawith open("my_class.json", "w") as f:json.dump(data, f)data_change.translate.insert(0.0, data)實(shí)現(xiàn)的效果如下:
總結(jié)
- 上一篇: DataFormatString格式化
- 下一篇: 宏山激光sigmatube套料软件多台电