吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1640|回复: 3
收起左侧

[会员申请] 申请会员ID:ai_po_jie

[复制链接]
吾爱游客  发表于 2023-4-22 09:10
1、申 请 I D:ai_po_jie
2、个人邮箱:wingerX@126.com
3、原创技术文章
-========================================================-
python 自定义日期控件开发


1. 创建自定义类
import tkinter
from tkinter import ttk
import calendar
import datetime


class DatePicker(ttk.Entry):

    def __init__(self, master=None, **kw):
        self._separator = kw.pop('separator', '-')
        if self._separator not in ['-','/']:
            self._separator = '-'

        super().__init__(master, **kw)

        self.set_state(kw.get('state', ''))

        self.style = ttk.Style(self)
        self._setup_style()
        self.configure(style='DatePicker')

        self._year = tkinter.IntVar()
        self._year.set(datetime.date.today().year)
        self._month = tkinter.IntVar()
        self._month.set(datetime.date.today().month)
        self._day = tkinter.IntVar()
        self._day.set(datetime.date.today().day)
        self._set_text()

        self._frame = tkinter.Toplevel(self, background='gray', borderwidth=1)
        self._frame.withdraw()                       #   隐藏窗口
        self._frame.overrideredirect(True)           #   显示下拉时,不带标题栏 (Toplevel是一个窗口)
        self._set_frame()

        self.bind('<Motion>', self._on_motion)
        self.bind('<Leave>', lambda e: self.state(['!active']))
        self.bind('<Button-1>', self._show_down_frame)
        self._top_frame.bind('<FocusOut>', self._on_focus_out)


    def _setup_style(self):
        """
        设置样式(复制TCombobox样式)
        :return:
        """
        self.style.layout('DatePicker', self.style.layout('TCombobox'))
        conf = self.style.configure('TCombobox')
        if conf:
            self.style.configure('DatePicker', **conf)
        maps = self.style.map('TCombobox')
        if maps:
            self.style.map('DatePicker', **maps)


    def _on_motion(self, event):
        x, y = event.x, event.y
        if 'disabled' not in self.state():
            if self.identify(x, y) == 'Combobox.rightdownarrow':
                self.state(['active'])
                self.configure(cursor='arrow')
            else:
                self.state(['!active'])
                self.configure(cursor='xterm')


    def _show_down_frame(self, event):
        """
        显示下拉
        :param event:
        :return:
        """
        if ('disabled' in self.state()) or (self.identify(event.x, event.y) != 'Combobox.rightdownarrow'):
            return

        if self._sp_year.winfo_ismapped():     #   _btn被绘制(下拉打开状态)
            self._frame.withdraw()             #   隐藏下拉窗口(关闭下拉)
        else:
            x = self.winfo_rootx()
            y = self.winfo_rooty()+ self.winfo_height()

            self._frame.geometry('+%i+%i' % (x,y))
            self._frame.deiconify()                     #   打开下拉(显示窗口)
            self._sp_year.focus_set()


    def _on_focus_out(self, event):
        if self.focus_get() == None and 'active' in  self.state():   #下拉打开再次点击下拉
            pass
        else:
            self._frame.withdraw()


    def _set_frame(self):
        """
        设置下拉界面
        :return:
        """
        self._top_frame = ttk.Frame(self._frame)
        self._top_frame.pack(fill='x')

        self._sp_year = ttk.Spinbox(self._top_frame, from_=1900, to=5000, width=6, textvariable=self._year)
        self._sp_year.grid(row=0, column=0, padx=2, pady=1)
        ttk.Label(self._top_frame, text='').grid(row=0, column=1, padx=2)

        self._sp_month = ttk.Spinbox(self._top_frame, from_=1, to=12, width=4, textvariable=self._month)
        self._sp_month.grid(row=0, column=2, padx=3, pady=1)
        ttk.Label(self._top_frame, text='').grid(row=0, column=3, padx=2)


        _middle_frame = ttk.Frame(self._frame)
        _middle_frame.pack(fill='x')
        self._initial_labels(_middle_frame)

        _bottom_frame = ttk.Frame(self._frame)
        _bottom_frame.pack(fill='x')
        _label_today = ttk.Label(_bottom_frame, text='今天: '+ str(datetime.date.today()))
        _label_today.pack(anchor='e', ipadx=8)
        _label_today.bind('<Motion>', self._on_label_today_motion)
        _label_today.bind('<Leave>', self._on_label_today_leave)
        _label_today.bind('<Button-1>', self._on_label_today_click)

        self._sp_year.configure(command=self._on_change)
        self._sp_year.bind('<KeyRelease>', self._on_spinbox_press)
        self._sp_year.bind('<Return>', self._on_year_return)

        self._sp_month.configure(command=self._on_change)
        self._sp_month.bind('<KeyRelease>', self._on_spinbox_press)
        self._sp_month.bind('<Return>', self._on_month_return)


    def _on_label_today_motion(self,event):
            event.widget.configure(foreground='DeepSkyBlue')


    def _on_label_today_leave(self, event):
            event.widget.configure(foreground=self.cget('background'))


    def _on_label_today_click(self, event):
        self._year.set(datetime.date.today().year)
        self._month.set(datetime.date.today().month)
        self._day.set(datetime.date.today().day)

        self._on_change()      #  通过_on_change()重新设置self._day_list
        self._set_text()
        self._frame.withdraw()


    def _on_year_return(self,event):
        if self._year.get() > int(event.widget.cget('to')):
            self._year.set(event.widget.cget('to'))
        if self._year.get() < int(event.widget.cget('from')):
            self._year.set(event.widget.cget('from'))

        self._sp_month.focus()
        self._on_change()


    def _on_month_return(self,event):
        if self._month.get() > int(event.widget.cget('to')):
            self._month.set(event.widget.cget('to'))
        if self._month.get() < int(event.widget.cget('from')):
            self._month.set(event.widget.cget('from'))

        self._sp_year.focus()
        self._on_change()


    def _on_spinbox_press(self, event):
        txt = event.widget.get()
        if event.keysym:
            if not txt.isdigit():
                event.widget.set(''.join(i for i in txt if i.isdigit()))


    def _initial_labels(self, parent):
        """
        初始化日期标签
        :param parent:
        :return:
        """
        week = ('', '', '', '', '', '', '')
        for i, item in enumerate(week):
            ttk.Label(parent, text=item.center(3)).grid(row=0, column=i)

        self._day_list = []
        self._label_list = []
        self._set_day_list()
        for i, item in enumerate(self._day_list):
            label = ttk.Label(parent, text=str(item[2]).rjust(2))
            label.grid(row= i // 7 + 1, column=item[3], padx=1)
            label.hint = item                #添加一个属性
            label['foreground'] ='Black'
            if item[1] != self._month.get():
                label['foreground'] = 'Gray'
            label['background'] = self.cget('background')
            if item[2] == self._day.get() and  item[1] == self._month.get():
                label['background'] = 'DeepSkyBlue'

            label.bind('<Button-1>', self._on_label_click)
            label.bind('<Motion>', self._on_label_motion)
            label.bind('<Leave>', self._on_label_leave)
            self._label_list.append(label)


    def _set_day_list(self):
        """
        设置日期列表
        :return:
        """
        for day in calendar.Calendar().itermonthdays4(self._year.get(), self._month.get()):
            self._day_list.append(day)


        if len(self._day_list) == 28:     #本月只有28天且一号为星期一
            for day in calendar.Calendar().itermonthdays4(self._year.get(), self._month.get() + 1):
                self._day_list.append(day)
                if len(self._day_list) == 35:
                    break


    def _on_change(self):
        self._day_list.clear()
        self._set_day_list()

        for i, label in enumerate(self._label_list):
            label.hint = self._day_list
            label['text'] = self._day_list[2]

            label['foreground'] ='Black'
            if self._day_list[1] != self._month.get():
                label['foreground'] = 'Gray'

            label['background'] = self.cget('background')
            if self._day_list[1] == self._month.get() and self._day_list[2] == self._day.get():
                label['background'] = 'DeepSkyBlue'


    def _set_text(self):
        """
        设置日期至文本框
        :return:
        """
        readonly = False
        if 'readonly' in self.state():
            readonly = True
            self.state(['!readonly'])

        txt = self._separator.join([str(self._year.get()), str(self._month.get()), str(self._day.get())])
        self.delete(0, 'end')
        self.insert(0, txt)
        if readonly:
            self.state(['readonly'])


    def _on_label_click(self, event):
        if event.widget.hint is not None:
            for label in self._label_list:
                if label != event.widget:     # 刷新背景色(修改默认日期的背景色)
                    label.configure(background=self.cget('background'))

            self._year.set(event.widget.hint[0])
            self._month.set(event.widget.hint[1])
            self._day.set(event.widget.hint[2])

            self._set_text()
            self._frame.withdraw()


    def _on_label_motion(self, event):
        if event.widget.hint is not None:
            event.widget.configure(background= 'SkyBlue')
            if event.widget.hint[1] == self._month.get() and event.widget.hint[2] == self._day.get():
                event.widget.configure(background='DeepSkyBlue')


    def _on_label_leave(self, event):
        if event.widget.hint is not None:
            event.widget.configure(background= self.cget('background'))
            if event.widget.hint[1] == self._month.get() and event.widget.hint[2] == self._day.get():
                event.widget.configure(background='DeepSkyBlue')


    def _set_date(self, text):
        """
        设置日期
        :param text:  被设置的日期文本
        :return:
        """
        try:
            formatstr = self._separator.join(['%Y','%m','%d'])
            cur_date = datetime.datetime.strptime(text, formatstr)
            self._year.set(cur_date.date().year)
            self._month.set(cur_date.date().month)
            self._day.set(cur_date.date().day)
            self._set_text()
        except Exception:
                raise ValueError("%s不是一个合法的日期" % text)

    def _get_date(self):
        return self.get()


    def set_state(self, *args):
        """
        设置状态
        :param args:
        :return:
        """
        if args:
            if ('disabled' in args) or ('readonly' in args):
                self.configure(cursor='arrow')
            elif ('!disabled' in args) or ('!readonly' in args):
                self.configure(cursor='xterm')
            self.state(args)

    date = property(_get_date, _set_date)


2. 测试主界面
import tkinter as tk
import datepicker


class GUI:

    def __init__(self):
        self.root = tk.Tk()
        self.root.title('演示')
        self.root.geometry("300x230+300+150")
        self.interface()

    def interface(self):
        """"界面编写位置"""
        self.Label0 = tk.Label(self.root, text="日  期")
        self.Label0.grid(row=0, column=0, padx=2)

        self.date = datepicker.DatePicker(self.root, width='10')
        self.date.grid(row=0, column=1, padx=2)

        self.Button = tk.Button(self.root, text="获取日期", width=7, command=self.show)
        self.Button.grid(row=0, column=2,  padx=2)

        self.text = tk.Text(self.root, width=30, height=10)
        self.text.grid(row=1, column=0, columnspan=3)


    def show(self):
        # 获取日期
        self.text.delete(0.0,'end')
        self.text.insert(1.0, f"日期1{self.date.date}\n")
        self.text.insert(1.0, f"日期2{self.date.date.replace('-', '/')}\n")


if __name__ == '__main__':
    a = GUI()
    a.root.mainloop()


3. 运行--略  (不能上传gif 图片)



发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hmily 发表于 2023-4-23 11:24
抱歉,未能达到申请要求,申请不通过,可以关注论坛官方微信(吾爱破解论坛),等待开放注册通知。
吾爱游客  发表于 2023-4-24 08:34
Hmily 发表于 2023-4-23 11:24
抱歉,未能达到申请要求,申请不通过,可以关注论坛官方微信(吾爱破解论坛),等待开放注册通知。

版主,你好。是不是没达到精华技术水准?还是需要其他什么要求。我是按照申请要求发的, 这个是我的原创作品。

点评

是的。。  详情 回复 发表于 2023-4-24 11:14
Hmily 发表于 2023-4-24 11:14
(^_^) 发表于 2023-4-24 08:34
版主,你好。是不是没达到精华技术水准?还是需要其他什么要求。我是按照申请要求发的, 这个是我的原创 ...

是的。。

本版积分规则

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-3-29 21:51

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表