2012-12-04 115 views
6

[已解決]請參閱下面有關運行kivy DatePicker小工具的接受答案和源代碼的應用。Kivy Date Picker Widget

我一直在學習Kivy,並決定將日期選取器小部件作爲學習練習。

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設置爲具有該日部分的日期對象。

我已經嘗試添加

self.date_label.bind(on_touch_down = self.set_date(date_cursor.day)) 

,但只得到了最大的遞歸誤差。

SOLUTION:

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() 
+1

此外,作爲評論,因爲它不是你的問題,但你不需要存儲在你的實例,如果你不會使用後的值,所以在populate_body中,'self.date_label'可以被' date_label'到處都是。作爲旁註的旁註,請尊重pep8:P,在函數調用中'='周圍沒有空格,每個類定義之間只有兩行和兩行。祝你有個美好的一天:)編輯:哦,也感謝爲kivy製作日期選擇器,我相信它可以對其他人有用:) – Tshirtman

+0

是的,我經歷了幾次迭代date_label和self.date_label,只是發生帖子以這種形式。 無論何時,當我看到東西時,我都會看到你的頭像。我開始認爲這是某種默認/模仿頭像! – Horba

+0

呵呵,好吧,我嘗試回答所有kivy問題^^ – Tshirtman

回答

3

你在結合做一個小的失誤,你通話的方法,而不是傳遞它(因此,你傳遞的self.set_date(date_cursor.day)的結果,但調用self.set_date電話self.populate_body太,所以你得到一個無限遞歸,只能通過python遞歸限制來停止。

你想要做的就是綁定方法,但是用date_cursor.day作爲第一個參數,對於這個partial功能,從functools是完美的。

self.date_label.bind(on_touch_down=partial(self.set_date, date_cursor.day))

創建一個新的fonction,那就像self.set_date,但date_cursor.day預裝作爲第一個參數。

編輯:另外,當你的部分函數被事件綁定調用時,它會接收其他參數,因此在你使用屁股回調函數/方法的參數結尾添加**args是個好習慣(這裏set_date )。

+0

謝謝,我知道它會是這樣的,但不能在不調用函數的情況下傳遞所需的參數。 functools!我今晚要再次處理這個問題並報告回來。 – Horba