[已解决] 请参阅下面的应用程序接受的答案和运行 kivy DatePicker 小部件的源代码.
[SOLVED] Please see below for application of accepted answer and source code for functioning kivy DatePicker widget.
我一直在学习 Kivy,并决定制作一个日期选择器小部件作为学习练习.
I've been learning Kivy and decided to make a date picker widgets as a learning exercise.
import kivy
kivy.require('1.4.0')
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.app import App
from datetime import date, timedelta
class DatePicker(BoxLayout):
def __init__(self, **kwargs):
super(DatePicker, self).__init__(**kwargs)
self.date = date.today()
self.orientation = "vertical"
self.header = BoxLayout(orientation = 'horizontal',
size_hint = (1, 0.2))
self.body = GridLayout(cols = 7)
self.add_widget(self.header)
self.add_widget(self.body)
self.populate_body()
self.populate_header()
def populate_header(self):
self.header.clear_widgets()
self.previous_month = Button(text = "<")
self.next_month = Button(text = ">")
self.current_month = Label(text = repr(self.date),
size_hint = (2, 1))
self.header.add_widget(self.previous_month)
self.header.add_widget(self.current_month)
self.header.add_widget(self.next_month)
def populate_body(self):
self.body.clear_widgets()
date_cursor = date(self.date.year, self.date.month, 1)
while date_cursor.month == self.date.month:
self.date_label = Label(text = str(date_cursor.day))
self.body.add_widget(self.date_label)
date_cursor += timedelta(days = 1)
# Not yet implimented ###
# def set_date(self, day):
# self.date = date(self.date.year, self.date.month, day)
# self.populate_body()
# self.populate_header()
#
# def move_next_month(self):
# 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)
# def move_previous_month(self):
# 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(App):
def build(self):
return DatePicker()
if __name__ == '__main__':
MyApp().run()
我遇到了障碍,不知道如何继续.我想添加一种方法,以便在单击 date_labels 时,它们将 self.date 设置为具有该日期部分的日期对象.
I've hit a road block and can't work out how to continue. I want to add a method such that when the date_labels are clicked, they set self.date to a date object with that day part.
我试过添加
self.date_label.bind(on_touch_down = self.set_date(date_cursor.day))
但只有最大递归错误.
import kivy
kivy.require('1.4.0')
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.app import App
from datetime import date, timedelta
from functools import partial
class DatePicker(BoxLayout):
def __init__(self, *args, **kwargs):
super(DatePicker, self).__init__(**kwargs)
self.date = date.today()
self.orientation = "vertical"
self.month_names = ('January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December')
if kwargs.has_key("month_names"):
self.month_names = kwargs['month_names']
self.header = BoxLayout(orientation = 'horizontal',
size_hint = (1, 0.2))
self.body = GridLayout(cols = 7)
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 = Button(text = "<")
previous_month.bind(on_press=partial(self.move_previous_month))
next_month = Button(text = ">", on_press = self.move_next_month)
next_month.bind(on_press=partial(self.move_next_month))
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))
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 filler in range(date_cursor.isoweekday()-1):
self.body.add_widget(Label(text=""))
while date_cursor.month == self.date.month:
date_label = Button(text = str(date_cursor.day))
date_label.bind(on_press=partial(self.set_date,
day=date_cursor.day))
if self.date.day == date_cursor.day:
date_label.background_normal, date_label.background_down = date_label.background_down, date_label.background_normal
self.body.add_widget(date_label)
date_cursor += timedelta(days = 1)
def set_date(self, *args, **kwargs):
self.date = date(self.date.year, self.date.month, kwargs['day'])
self.populate_body()
self.populate_header()
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(App):
def build(self):
return DatePicker()
if __name__ == '__main__':
MyApp().run()
你在绑定中犯了一个小错误,你调用方法而不是传递它(因此,你传递了 self.set_date(date_cursor.day)
的结果,但是调用 self.set_date
也会调用 self.populate_body
,所以你得到在无限递归中,只被python递归限制停止.
you do a small mistake in your binding, you call the method instead of passing it (thus, you pass the result of self.set_date(date_cursor.day)
, but calling self.set_date
calls self.populate_body
too, so you get in an infinite recursion, only stopped by python recursion limit.
你想要做的是绑定方法,但使用 date_cursor.day
作为第一个参数,对于这个 partial
函数,来自 functools
完美.
What you want to do is bind the method but with date_cursor.day
as a first parameter, for this the partial
function, from functools
is perfect.
<代码>self.date_label.bind(on_touch_down=partial(self.set_date, date_cursor.day))
创建一个新函数,与 self.set_date 类似,但将 date_cursor.day 作为第一个参数预加载.
Creates a new fonction, that is just like self.set_date, but with date_cursor.day preloaded as a first argument.
另外,当你的部分函数被事件绑定调用时,它会接收其他参数,所以在函数的参数末尾添加 **args
是一个好习惯/使用 ass 回调的方法(此处为 set_date
).
edit: also, when your partial function is called by the event binding, it will recieve other arguments, so it's a good habit to add **args
at the end of your arguments in functions/methods you use ass callbacks (here set_date
).
这篇关于Kivy 日期选择器小部件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!