Skip to content

Instantly share code, notes, and snippets.

@kengoon
Last active November 22, 2023 08:44
Show Gist options
  • Save kengoon/d064ad49f4aa2212897afd69f97578dc to your computer and use it in GitHub Desktop.
Save kengoon/d064ad49f4aa2212897afd69f97578dc to your computer and use it in GitHub Desktop.
A re-implementation of Adam's kivy widget (https://stackoverflow.com/users/1281548/adam) (https://stackoverflow.com/questions/13714074/kivy-date-picker-widget#) in Material Design using KivyMD
from kivy.event import EventDispatcher
from kivy.metrics import dp
from kivy.properties import ListProperty, StringProperty
from kivymd.uix.behaviors import FakeRectangularElevationBehavior
from kivymd.uix.card import MDCard
from kivy.uix.behaviors import ToggleButtonBehavior
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivymd.uix.button import MDRaisedButton
from kivymd.app import MDApp
from datetime import date, timedelta
from kivy.lang import Builder
Builder.load_string("""
<DateButton>:
elevation: .1
radius: dp(10)
ripple_behavior: True
Label:
text: root.text
color: root.text_color
""")
class DateButton(MDCard, FakeRectangularElevationBehavior, ToggleButtonBehavior):
text_color = ListProperty([0, 0, 0, .6])
text = StringProperty("")
def on_state(self, widget, value):
if value == 'down':
self.md_bg_color = self.theme_cls.primary_color
self.text_color = [1, 1, 1, 1]
else:
self.md_bg_color = [1, 1, 1, 1]
self.text_color = [0, 0, 0, .6]
class DatePicker(BoxLayout, EventDispatcher):
# butt
def __init__(self, *args, **kwargs):
super(DatePicker, self).__init__(**kwargs)
self.register_event_type("on_select")
self.date = date.today()
self.days = (
"Mon",
"Tue",
"Wed",
"Thur",
"Fri",
"Sat",
"Sun"
)
self.orientation = "vertical"
self.month_names = (
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
)
if "month_names" in kwargs:
self.month_names = kwargs['month_names']
self.header = BoxLayout(orientation='horizontal',
size_hint=(1, 0.2))
self.body = GridLayout(cols=7, spacing=dp(20))
self.add_widget(self.header)
self.add_widget(self.body)
self.populate_body()
self.populate_header()
def populate_header(self, *args, **kwargs):
self.header.clear_widgets()
previous_month = MDRaisedButton(text="<", pos_hint={"center_y": .5}, on_release=self.move_previous_month)
previous_month.bind()
next_month = MDRaisedButton(text=">", on_release=self.move_next_month, pos_hint={"center_y": .5})
month_year_text = self.month_names[self.date.month - 1] + ' ' + str(self.date.year)
current_month = Label(text=month_year_text, size_hint=(2, 1), color=[0, 0, 0, .6])
self.header.add_widget(previous_month)
self.header.add_widget(current_month)
self.header.add_widget(next_month)
def populate_body(self, *args, **kwargs):
self.body.clear_widgets()
date_cursor = date(self.date.year, self.date.month, 1)
for day in self.days:
self.body.add_widget(Label(text=day, color=[0, 0, 0, .5]))
for filler in range(date_cursor.isoweekday() - 1):
self.body.add_widget(Label(text=""))
while date_cursor.month == self.date.month:
date_label = DateButton(text=str(date_cursor.day), group="date")
date_label.bind(
on_release=lambda x, _date=int(date_label.text): self.set_date(
day=date(self.date.year, self.date.month, _date)
)
)
if self.date.day == date_cursor.day:
date_label.state = "down"
self.body.add_widget(date_label)
date_cursor += timedelta(days=1)
def set_date(self, day):
self.date = day
self.dispatch("on_select", day)
def on_select(self, day):
pass
def move_next_month(self, *args, **kwargs):
if self.date.month == 12:
self.date = date(self.date.year + 1, 1, self.date.day)
else:
self.date = date(self.date.year, self.date.month + 1, self.date.day)
self.populate_header()
self.populate_body()
def move_previous_month(self, *args, **kwargs):
if self.date.month == 1:
self.date = date(self.date.year - 1, 12, self.date.day)
else:
self.date = date(self.date.year, self.date.month - 1, self.date.day)
self.populate_header()
self.populate_body()
class MyApp(MDApp):
def build(self):
box = BoxLayout(padding=dp(20))
box.add_widget(DatePicker())
return box
if __name__ == '__main__':
MyApp().run()
@kengoon
Copy link
Author

kengoon commented Feb 2, 2022

datepicker

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment