(原创)Python Tkinter日期选择(日历)‘控件’

  • Post author:
  • Post category:python




前言



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('<FocusOut>', 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('<FocusOut>', 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('<Double-Button-1>', 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()



版权声明:本文为m0_67962909原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。