前言
Tkinter模块("Tk 接口")是Python的标准Tk GUI工具包的接口
作为一个业余的为方便自己工作的自学者来说,我写的程序都是用TK模块创建GUI。但TK并没有提供日期选择控件。
之前我一直使用网上大神写的日期选择器,如下图
使用起来无法双击选择日期,有一点不方便。
所以我自己用tksheet写了一个日期选择器。
不一定很完美,至少我自己用着还不错,今天分享给大家
不足之处,可能调用有点麻烦 需要复制两段代码到tk窗体主程序中,如果有大神能帮我改的更方便调用,万分感谢
# -*- coding:utf-8 -*-
import tkinter as tk
import calendar
import datetime
import tksheet
datetime = calendar.datetime.datetime
timedelta = calendar.datetime.timedelta
class tkcalendar(tk.Toplevel):
def __init__(self,x,y):
super().__init__()
self.setup_UI(x,y)
def setup_UI(self,x,y):
self.title('日期选择窗 作者:包家三少')
ww = 300 # 设置窗口 宽度
wh = 250 # 设置窗口 高度
self.geometry("%dx%d+%d+%d" % (ww, wh, x, y))
calendar.setfirstweekday(firstweekday=6) # 将星期天设置为一周第一天
list_date1 = calendar.monthcalendar(datetime.now().year, datetime.now().month)
list_date = []
for i in list_date1: # 替换list_date1列表中 0
list_date2 = []
for j in i:
if j == 0 and len(str(j)) == 1:
j = ''
elif j != 0 and len(str(j)) == 1:
j = '0' + str(j)
if len(list_date) <= 7:
list_date2.append(j)
list_date.append(list_date2)
self.frame1 = tk.Frame(self)
self.frame1.pack()
var_year = tk.StringVar()
self.Spinbox_year = tk.Spinbox(self.frame1, from_=1, to=9999, textvariable=var_year, width=4, font="宋体, 16",
command=self.update_calendar)
self.Spinbox_year.grid(row=0, column=0, padx=5, pady=5)
var_year.set(datetime.now().year)
def unfocus(event):#失去焦点后更新日期表
self.update_calendar()
self.Spinbox_year.bind('', unfocus) # Spinbox_year失去焦点后执行函数 unfocus
self.Label_year = tk.Label(self.frame1, text='年', font="宋体, 16")
self.Label_year.grid(row=0, column=1, padx=5, pady=5)
var_month = tk.StringVar()
self.Spinbox_month = tk.Spinbox(self.frame1, from_=1, to=12, textvariable=var_month, width=4, font="宋体, 16",
command=self.update_calendar)
self.Spinbox_month.grid(row=0, column=2, padx=5, pady=5)
var_month.set(datetime.now().month)
self.Spinbox_month.bind('', unfocus)# Spinbox_month失去焦点后执行函数 unfocus
self.Label_month = tk.Label(self.frame1, text='月', font="宋体, 16")
self.Label_month.grid(row=0, column=3, padx=5, pady=5)
self.var_date_choose = tk.StringVar()
self.Entry_date_choose = tk.Entry(self.frame1, textvariable=self.var_date_choose)
self.Entry_date_choose.grid(row=0, column=5, padx=5, pady=5)
self.Entry_date_choose.grid_forget()
self.frame2 = tk.Frame(self)
self.frame2.pack()
self.sheet = tksheet.Sheet(self.frame2,
page_up_down_select_row=True,
expand_sheet_if_paste_too_big=True,
column_width=35,
startup_select=(0, 1, "rows"),
row_height="1",
headers=['日', '一', "二", '三', '四', '五', '六'],
height=165, # height and width arguments are optional
width=290,
total_rows=6, # if you want to set empty sheet dimensions at startup
total_columns=7,
data=list_date
)
self.sheet.enable_bindings()
self.sheet.change_theme("light blue")
self.sheet.highlight_columns([0, 6], bg="light blue", fg="purple")
self.sheet.readonly_columns(columns=[0], readonly=True, redraw=True)
self.sheet.font(newfont=("宋体", 12, "normal"), reset_row_positions=True)
self.sheet.readonly_columns(columns=[0, 1, 2, 3, 4, 5, 6], readonly=True, redraw=True)
self.sheet.pack(anchor=tk.W)
def sheet_double_clicked(event):
self.sure()
self.sheet.bind('', sheet_double_clicked)
self.frame3 = tk.Frame(self)
self.frame3.pack()
self.Button_sure = tk.Button(self.frame3, text='确定', font="宋体, 12", borderwidth= 2,relief = tk.GROOVE ,command=self.sure)
self.Button_sure.grid(row=0, column=0, padx=5, pady=5)
self.Button_today = tk.Button(self.frame3, text='今天', font="宋体, 12", borderwidth= 2,relief = tk.GROOVE , command=self.today)
self.Button_today.grid(row=0, column=1, padx=5, pady=5)
self.Button_exit = tk.Button(self.frame3, text='取消', font="宋体, 12", borderwidth= 2,relief = tk.GROOVE ,command=self.cancel)
self.Button_exit.grid(row=0, column=2, padx=5, pady=5)
#--------------------------------------------
def update_calendar(self): #更新日历
row_num1 = self.sheet.get_total_rows()
if row_num1 > 0:
for t in range(row_num1):
self.sheet.delete_row(idx=0, deselect_all=False, redraw=True)
list_date1 = calendar.monthcalendar(int(self.Spinbox_year.get()), int(self.Spinbox_month.get()))
print(list_date1, 'ppp')
list_date = []
for i in list_date1: # 替换list_date1列表中 0
list_date2 = []
for j in i:
if j == 0 and len(str(j)) == 1:
j = ''
elif j != 0 and len(str(j)) == 1:
j = '0' + str(j)
if len(list_date) <= 7:
list_date2.append(j)
list_date.append(list_date2)
self.sheet.set_sheet_data(list_date, verify=False)
def sure(self):
sure_year = self.Spinbox_year.get()
sure_month = self.Spinbox_month.get()
if len(sure_month) ==1:
sure_month = '0'+ sure_month
sure_day = self.sheet.get_cell_data(self.sheet.get_currently_selected()[0],
self.sheet.get_currently_selected()[1])
if sure_day =='':return
else:
sure_date = sure_year + '-' + sure_month + '-' + sure_day
self.var_date_choose.set(sure_date)
self.date_get = [self.Entry_date_choose.get()] # 设置数据
self.destroy() # 销毁窗口
def today(self):
to_day =str(datetime.now().strftime("%Y-%m-%d"))
self.var_date_choose.set(to_day)
self.date_get = [self.Entry_date_choose.get()]
self.destroy() # 销毁窗口today
def cancel(self):
self.date_get = None # 空!
self.destroy()
if __name__ == '__main__':
root1 = tkcalendar(300,300)
root1.wait_window()
#调用举例
# -*- coding: utf-8 -*-
import tkinter as tk
import tkcalendar
class tkcalendar_test():
def __init__(self):
self.setupUI()
def setupUI(self):
self.root = tk.Tk()
# 设置tk窗口在屏幕中心显示
sw = self.root.winfo_screenwidth() # 得到屏幕宽度
sh = self.root.winfo_screenheight() # 得到屏幕高度
ww = 200 # 设置窗口 宽度
wh = 60 # 设置窗口 高度
x = (sw - ww) / 2
y = (sh - wh) / 2
self.root.geometry("%dx%d+%d+%d" % (ww, wh, x, y))
# --------------------------------------------------------------------------------------------
self.Frame_row1 = tk.Frame(self.root)
self.Frame_row1.pack()
self.var_test = tk.StringVar()
self.Entry_test = tk.Entry(self.Frame_row1, width=10, textvariable=self.var_test, font="宋体, 12",
justify='center', )
self.Entry_test.grid(row=0, column=0, padx=5, pady=5)
self.Button_test = tk.Button(self.Frame_row1, width=2, text='*', font="宋体, 12",
justify='center',
command=lambda: self.tkcalendar_get_date(self.Entry_test.winfo_rootx(),
self.Entry_test.winfo_rooty() + 20))
self.Button_test.grid(row=0, column=1, padx=5, pady=5)
self.root.mainloop()
def tkcalendar_get_date(self, x, y): # x,y位Entry的坐标位置
# 接收弹窗的数据
res = self.tkcalendar_ask_date(x, y)
if res is None: return
self.var_test.set(res[0])
def tkcalendar_ask_date(self, x, y):
inputDialog = tkcalendar.tkcalendar(x, y)
self.root.wait_window(inputDialog) # 这一句很重要!!!
return inputDialog.date_get
if __name__ == '__main__':
app = tkcalendar_test()
调用代码:
# -*- coding: utf-8 -*-
import tkinter as tk
import tkcalendar
class tkcalendar_test():
def __init__(self):
self.setupUI()
def setupUI(self):
self.root = tk.Tk()
# 设置tk窗口在屏幕中心显示
sw = self.root.winfo_screenwidth() # 得到屏幕宽度
sh = self.root.winfo_screenheight() # 得到屏幕高度
ww = 200 # 设置窗口 宽度
wh = 60 # 设置窗口 高度
x = (sw - ww) / 2
y = (sh - wh) / 2
self.root.geometry("%dx%d+%d+%d" % (ww, wh, x, y))
# --------------------------------------------------------------------------------------------
self.Frame_row1 = tk.Frame(self.root)
self.Frame_row1.pack()
self.var_test = tk.StringVar()
self.Entry_test = tk.Entry(self.Frame_row1, width=10, textvariable=self.var_test, font="宋体, 12",
justify='center',)
self.Entry_test.grid(row=0, column=0, padx=5, pady=5)
# 调用日历控件---------------------------------------------------
date_choose = lambda: [
self.var_test.set(date)
for date in [self.tkcalendar_get_date(self.Entry_test.winfo_rootx(),
self.Entry_test.winfo_rooty() + 20)]]
self.Button_test = tk.Button(self.Frame_row1, width=2, text='*', font="宋体, 12",
justify='center',
command = date_choose)
self.Button_test.grid(row=0, column=1, padx=5, pady=5)
# 调用日历控件---------------------------------------------------
self.root.mainloop()
#-------------------------------------------------------------
#这一部分需要复制到 tk窗体代码中
def tkcalendar_get_date(self,x,y):#x,y位Entry的坐标位置
# 接收弹窗的数据
res = self.tkcalendar_ask_date(x,y)
if res is None: return
return(res[0])
#self.var_test.set(res[0])
def tkcalendar_ask_date(self,x,y):
inputDialog = tkcalendar.tkcalendar(x,y)
self.root.wait_window(inputDialog) # 这一句很重要!!!
return inputDialog.date_get
#--------------------------------------------------------------
if __name__ == '__main__':
app = tkcalendar_test()