写在前面的话
今日目标,做一个扇贝学习进度图
功能包括:
1、用Tkinter
设置界面,用户需要输入四项信息
(1)每天单词的学习计划数量
(2)每天阅读的学习计划数量
(3)每天听力的学习计划数量
(4)输入扇贝ID
2、根据用户输入数据,计算年度学习计划数量
3、根据用户输入的ID,读取扇贝中2020年已经学习的内容。分别计算单词、阅读、听力的总数量
4、利用Tkinter
的Canvas
组件,将数据做成进度条
界面预览
界面设计
老规矩,不想看介绍的,可以直接翻到最后看代码
关于Tkinter入门的Label(显示文本)、gird(布局为网格)、Button(按钮)三个组件操作,可以看Tkinter入门:制作一个日历
今天主要用到的组件是Label(显示文本)、Button(按钮)、Canvas(画框,用于显示进度)、place(放置位置)、Entry(文本输入)
导入库
import ShanbeyRecord
import tkinter as tk
from tkinter.messagebox import showinfo
import time
-
ShanbeyRecord
:用于扇贝查卡 -
tkinter
:用于制作界面 -
showinfo
:如果信息输入错误,用于显示报错信息 -
time
:控制进度条速度
创建窗口
window = tk.Tk() # 创建主窗口,名字为window
window.title('Progress') # 窗口名称
window.geometry('700x450') # 窗口大小
bgcolor = '#F0FFF0' # 背景颜色
fgcolor = 'teal' # 前景颜色
window.configure(background=bgcolor) # 给窗口上色
其中窗口颜色,用英文字母teal
,或者RGB形式#F0FFF0
都可以,至于这个颜色对应的RGB是什么,百度RGB颜色,网上一大堆,你喜欢什么颜色,就改什么。
显示文字:Label
先显示标题
tk.Label(window, text='2020', background=bgcolor, font=('Helvetica',40,'bold italic'), foreground=fgcolor).place(x=280, y=30)
text='2020'
:文本内容
background=bgcolor
:背景色
font=('Helvetica',40,'bold italic')
:字体设置,包括字体+大小+加粗、倾斜
foreground=fgcolor
:前景色
place(x=280, y=30)
:放置的坐标位置
显示输入信息,每天的目标Your Goal (Every Day)
和扇贝IDShanbey ID
,设置方式和前面一致
tk.Label(window, text='Your Goal (Every Day)', background=bgcolor, font=('Helvetica',14,'bold italic'), foreground=fgcolor).place(x=50, y=120)
tk.Label(window, text='Shanbey ID', background=bgcolor, font=('Helvetica',14,'bold italic'), foreground=fgcolor).place(x=50, y=170)
显示输入框:Entry
EntWord = tk.Entry(window, textvariable=tk.StringVar(value='word number'), width=12, fg=fgcolor, font=('Helvetica',10,'italic'))
EntWord.place(x=300, y=125)
EntRead = tk.Entry(window, textvariable=tk.StringVar(value='read number'), width=12, fg=fgcolor, font=('Helvetica',10,'italic'))
EntRead.place(x=425, y=125)
EntListen = tk.Entry(window, textvariable=tk.StringVar(value='listen number'), width=12, fg=fgcolor, font=('Helvetica',10,'italic'))
EntListen.place(x=550, y=125)
EntID = tk.Entry(window, textvariable=tk.StringVar(value='ID:must be number'), width=20, fg=fgcolor, font=('Helvetica',10,'italic'))
EntID.place(x=180, y=175)
textvariable=tk.StringVar(value='word number')
:默认显示文字
width=12
:输入框宽度
fg=fgcolor
:颜色设置
font=('Helvetica',10,'italic')
:字体设置
EntWord.place(x=300, y=125)
:放置位置
设计进度条:Canvas
# 设置进度条标签
tk.Label(window, text='Word', background=bgcolor, font=('Helvetica',16,'bold italic'), foreground=fgcolor).place(x=50, y=100+150)
tk.Label(window, text='Read', background=bgcolor, font=('Helvetica',16,'bold italic'), foreground=fgcolor).place(x=50, y=150+150)
tk.Label(window, text='Listen', background=bgcolor, font=('Helvetica',16,'bold italic'), foreground=fgcolor).place(x=50, y=200+150)
# 设置进度条
CanvasWord = tk.Canvas(window, width=465, height=22, bg="white")
CanvasWord.place(x=120, y=100+150)
CanvasRead = tk.Canvas(window, width=465, height=22, bg="white")
CanvasRead.place(x=120, y=150+150)
CanvasListen = tk.Canvas(window, width=465, height=22, bg="white")
CanvasListen.place(x=120, y=200+150)
Canvas
是画布,下次详细讲。今天就是了解一下基础操作。
width=465
:宽度
height=22
:高度
bg="white"
:背景色
按钮设计:Button
StartButton = tk.Button(window,
text='Let Go!', # 文字
font=('Helvetica',14,'bold italic'), # 字体
foreground=fgcolor, # 前景色
background=bgcolor, # 背景色
activebackground='white', # 点击时的背景色
activeforeground=fgcolor, # 点击时的前景色
relief='raised', # 边框样式
command=Start) # 点击时出发的动作,这边定义了一个start函数
StartButton.place(x=550, y=160) # 放置位置
界面设计就搞定啦~~
接下来我们开始设计具体的事件
事件设计
在Button中,我们最后设置了command=Start
,也就是,按下按钮后,要进行一个Start
操作。接下来我们来写Start
函数
计算目标值
def Start():
# 获取输入的每天目标
GoalWord = EntWord.get()
GoalRead = EntRead.get()
GoalListen = EntListen.get()
# 判断是不是输入的是数字,如果不是,窗口提示
try:
NumWord = int(GoalWord)
NumRead = int(GoalRead)
NumListen = int(GoalListen)
except:
showinfo(message='每月目标输入错误,请输入纯数字')
return False
# 一年有365天
GoalWord = NumWord*365
GoalRead = NumRead*365
GoalListen = NumListen*365
# 获取目标值
tk.Label(window, text=str(GoalWord), background=bgcolor, font=('Helvetica',13,'bold italic'), foreground=fgcolor).place(x=590, y=100+150)
tk.Label(window, text=str(GoalRead), background=bgcolor, font=('Helvetica',13,'bold italic'), foreground=fgcolor).place(x=590, y=150+150)
tk.Label(window, text=str(GoalListen), background=bgcolor, font=('Helvetica',13,'bold italic'), foreground=fgcolor).place(x=590, y=200+150)
当输入正确的数字时,右下角会对应显示一年的目标量
如果输入错误时,利用showinfo
跳出报错窗口
获取扇贝数据
def Start():
--------------------
# 读取扇贝数据
ID = EntID.get()
try:
ShanbeyRecord.ReadRecond(int(ID))
Record = ShanbeyRecord.ReadRecond(ID)
Word = Record.Word
Read = Record.Read
Listen = Record.Listen
except:
showinfo(message='ID输入错误,请输入纯数字\n'+
'可通过扇贝网页版,右上角【我的打卡】,获取打卡网址\n'+
'网址是https://www.shanbay.com/checkin/user/*******/\n'+
'最后一串数字即为ID')
return False
这边就不详细将扇贝数据是怎么获取的了,之前爬虫都讲了好多。这边直接调用ShanbeyRecord.py
,这个文件附在最后。如果ID输入错误,同样系统会报错。这边要注意,这个ID必须是数字,不能是字母!
显示进度条
我们单独写一个函数,用来显示进度条。因为单词、听力、阅读的进度条都是一样的,没必要写3遍
# 显示进度条
def ShowProgress(canvas, number, total):
fill_line = canvas.create_rectangle(1.5, 1.5, 0, 23, width=0, fill=fgcolor)
x = total # total代表的进度条的总数目,就是目标数字
n = 465/x # 465是进度条的尺寸,每一次前进n
for i in range(number): # number时目前学习的数字
n = n + 465/x # 每次进度条往前加465/x
canvas.coords(fill_line, (0, 0, n, 60))
window.update() # 窗口更新
time.sleep(1/number) # 控制进度条的速度
然后在Start
函数最后,调用ShowProgress
函数
def Start():
-----------
ShowProgress(CanvasWord, Word, GoalWord)
ShowProgress(CanvasRead, Read, GoalRead)
ShowProgress(CanvasListen, Listen, GoalListen)
界面代码
# -*- coding: utf-8 -*-
"""
Created on Sat Mar 21 16:10:23 2020
@author: zhaoy
"""
import ShanbeyRecord
import tkinter as tk
from tkinter.messagebox import showinfo
import time
window = tk.Tk() # 创建主窗口
window.title('Progress') # 窗口名称
window.geometry('700x450') # 窗口大小
bgcolor = '#F0FFF0'#'lightcyan' # 背景颜色
fgcolor = 'teal' #前景颜色
window.configure(background=bgcolor) # 给窗口上色
# 显示标题
tk.Label(window, text='2020', background=bgcolor, font=('Helvetica',40,'bold italic'), foreground=fgcolor).place(x=280, y=30)
# 显示输入信息框
tk.Label(window, text='Your Goal (Every Day)', background=bgcolor, font=('Helvetica',14,'bold italic'), foreground=fgcolor).place(x=50, y=120)
tk.Label(window, text='Shanbey ID', background=bgcolor, font=('Helvetica',14,'bold italic'), foreground=fgcolor).place(x=50, y=170)
#
EntWord = tk.Entry(window, textvariable=tk.StringVar(value='word number'), width=12, fg=fgcolor, font=('Helvetica',10,'italic'))
EntWord.place(x=300, y=125)
EntRead = tk.Entry(window, textvariable=tk.StringVar(value='read number'), width=12, fg=fgcolor, font=('Helvetica',10,'italic'))
EntRead.place(x=425, y=125)
EntListen = tk.Entry(window, textvariable=tk.StringVar(value='listen number'), width=12, fg=fgcolor, font=('Helvetica',10,'italic'))
EntListen.place(x=550, y=125)
EntID = tk.Entry(window, textvariable=tk.StringVar(value='ID:must be number'), width=20, fg=fgcolor, font=('Helvetica',10,'italic'))
EntID.place(x=180, y=175)
#
# 设置进度条标签
tk.Label(window, text='Word', background=bgcolor, font=('Helvetica',16,'bold italic'), foreground=fgcolor).place(x=50, y=100+150)
tk.Label(window, text='Read', background=bgcolor, font=('Helvetica',16,'bold italic'), foreground=fgcolor).place(x=50, y=150+150)
tk.Label(window, text='Listen', background=bgcolor, font=('Helvetica',16,'bold italic'), foreground=fgcolor).place(x=50, y=200+150)
#
# 设置进度条
CanvasWord = tk.Canvas(window, width=465, height=22, bg="white")
CanvasWord.place(x=120, y=100+150)
CanvasRead = tk.Canvas(window, width=465, height=22, bg="white")
CanvasRead.place(x=120, y=150+150)
CanvasListen = tk.Canvas(window, width=465, height=22, bg="white")
CanvasListen.place(x=120, y=200+150)
#
# 显示进度条
def ShowProgress(canvas, number, total):
fill_line = canvas.create_rectangle(1.5, 1.5, 0, 23, width=0, fill=fgcolor)
x = total # 未知变量,可更改
n = 465/x # 465是矩形填充满的次数
for i in range(number):
n = n + 465/x
canvas.coords(fill_line, (0, 0, n, 60))
window.update()
time.sleep(1/number) # 控制进度条流动的速度
def Start():
# 获取输入的每天目标
GoalWord = EntWord.get()
GoalRead = EntRead.get()
GoalListen = EntListen.get()
# 判断是不是输入的是数字,如果不是,窗口提示
try:
NumWord = int(GoalWord)
NumRead = int(GoalRead)
NumListen = int(GoalListen)
except:
showinfo(message='每月目标输入错误,请输入纯数字')
return False
# 一年有365天
GoalWord = NumWord*365
GoalRead = NumRead*365
GoalListen = NumListen*365
# 获取目标值
tk.Label(window, text=str(GoalWord), background=bgcolor, font=('Helvetica',13,'bold italic'), foreground=fgcolor).place(x=590, y=100+150)
tk.Label(window, text=str(GoalRead), background=bgcolor, font=('Helvetica',13,'bold italic'), foreground=fgcolor).place(x=590, y=150+150)
tk.Label(window, text=str(GoalListen), background=bgcolor, font=('Helvetica',13,'bold italic'), foreground=fgcolor).place(x=590, y=200+150)
#
# 读取扇贝数据
ID = EntID.get()
try:
ShanbeyRecord.ReadRecond(int(ID))
Record = ShanbeyRecord.ReadRecond(ID)
Word = Record.Word
Read = Record.Read
Listen = Record.Listen
except:
showinfo(message='ID输入错误,请输入纯数字\n'+
'可通过扇贝网页版,右上角【我的打卡】,获取打卡网址\n'+
'网址是https://www.shanbay.com/checkin/user/*******/\n'+
'最后一串数字即为ID')
return False
#
ShowProgress(CanvasWord, Word, GoalWord)
ShowProgress(CanvasRead, Read, GoalRead)
ShowProgress(CanvasListen, Listen, GoalListen)
#
# button按钮
# relief must be flat, groove, raised, ridge, solid, or sunken
StartButton = tk.Button(window,
text='Let Go!',
font=('Helvetica',14,'bold italic'),
foreground=fgcolor,
background=bgcolor,
activebackground='white',
activeforeground=fgcolor,
relief='raised',
command=Start)
StartButton.place(x=550, y=160)
window.mainloop()
爬虫代码
# -*- coding: utf-8 -*-
"""
Created on Sat Mar 21 16:50:05 2020
@author: zhaoy
"""
import requests # 获取网页数据
import datetime
import xlwt
import pandas as pd
class Shanbey():
def __init__(self, name, read, listen):
self.Word = name
self.Read = read
self.Listen = listen
def SaveRecond(ID):
# 准备表格
workbook = xlwt.Workbook() #定义workbook
sheet = workbook.add_sheet('2020') #添加sheet
head = ['date', 'bdc','listen','read','time_bdc','time_listen','time_read']
for h in range(len(head)):
sheet.write(0, h, head[h]) #把表头写到Excel里面去
ExcelRow = 1; #定义Excel表格的行数,从第二行开始写入,第一行已经写了表头
# 读取数据
try:
for Page in range(1,10):
Web = "https://www.shanbay.com/api/v1/checkin/user/"+str(ID)+"/"+"?page="+str(Page)
Res = requests.get(Web)
DataEveryPage = Res.json()
End = str(datetime.date(2020,1,1)).split(" ")[0]
for data in DataEveryPage['data']:
if data['info']!='':
if data['checkin_date'] >= End:
sheet.write(ExcelRow, 0, data['checkin_date'])
try:
sheet.write(ExcelRow, 1, data['stats']['bdc']['num_today'])
sheet.write(ExcelRow, 4, data['stats']['bdc']['used_time'])
except:
sheet.write(ExcelRow, 1, 0)
try:
sheet.write(ExcelRow, 2, data['stats']['listen']['num_today'])
sheet.write(ExcelRow, 5, data['stats']['listen']['used_time'])
except:
sheet.write(ExcelRow, 2, 0)
sheet.write(ExcelRow, 5, 0)
try:
sheet.write(ExcelRow, 3, data['stats']['read']['num_today'])
sheet.write(ExcelRow, 6, data['stats']['read']['used_time'])
except:
sheet.write(ExcelRow, 3, 0)
sheet.write(ExcelRow, 6, 0)
ExcelRow += 1
else:
break
workbook.save('Summary2020.xls')
return True
except:
return False
def ReadRecond(ID):
if SaveRecond(ID):
df = pd.read_excel('Summary2020.xls')
df['date'] = pd.to_datetime(df['date'])
df = df.set_index('date') # 将date设置为index
Record = Shanbey(df['bdc'].sum(),df['read'].sum(),df['listen'].sum())
return Record
else:
return False
#ID = ********
#Record = ReadRecond(ID)
#print(Record.Word)