2012-12-04 21 views
6

[ÇÖZME] Fonksiyonel kivy DatePicker widget'ı için kabul edilen cevap ve kaynak kodunun uygulanması için lütfen aşağıya bakın.Kivy Date Picker Widget

Kivy'yi öğrendim ve bir öğrenme egzersiz aracı olarak bir tarih seçici widget'ları yapmaya karar verdim.

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

Bir yol bloğuna vurdum ve nasıl devam edeceğimi bilemiyorum. Date_labels tıklandığında, self.date öğesini o gün parçasına sahip bir tarih nesnesine ayarlayacak bir yöntem eklemek istiyorum.

Ben

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

ekleyerek denedim ama sadece maksimum özyineleme hataları var.

ÇÖZÜM: Eğer senin bağlayıcı içinde ufak bir hata yapmak

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

Ayrıca, bir soru olarak, sizin sorunuz değil, örneğinizde saklamak zorunda değilsiniz, sonra değeri kullanmayacaksanız, bu yüzden populate_body içinde, 'self.date_label' sadece ile değiştirilebilir. date_label' her yerde. Yan notun bir yan notu olarak, lütfen pep8: P'ye, bir fonlama çağrısında '=' etrafında boşluk bırakmayın, iki ve her sınıf tanımı arasında sadece iki satıra dikkat edin. iyi günler :) edit: oh ayrıca kivy için bir tarih seçici yapmak için teşekkürler, eminim başkalarına yararlı olabilir :) – Tshirtman

+0

Evet, date_label ve self.date_label birkaç iterations üzerinden gitti ve sadece oldu bu formda. Avatarı her yerde görüyorum, her ne zaman bir şeyler arıyorsam. Bir çeşit varsayılan/meme avatarı olduğunu düşünmeye başlamıştım! – Horba

+0

Hehe, tüm kivy sorularına cevap vermeye çalışıyorum ^^ – Tshirtman

cevap

3

, sen çağrı yöntem yerine (o geçen böylece sen self.set_date(date_cursor.day) sonucunu geçmesi, ancak arama self.set_date aramalar self.populate_body çok Bu nedenle, sonsuz bir özyinelemeye girersiniz, sadece python özyineleme sınırı tarafından durduruldu

Yapmak istediğiniz şey, yönteme bağlanır ancak date_cursor.day ile ilk parametre olarak, danişlevi mükemmeldir.

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

o ancak ilk argüman olarak önceden yüklenmiş date_cursor.day ile, sadece self.set_date gibidir, yeni fonksyonunun oluşturur.

düzenleme: ayrıca sizin kısmi fonksiyon olay bağlanarak çağrıldığında, diğer argümanlar alacaksınız, o yüzden burada (eğer eşek geri aramalar kullanmak set_date işlevleri/yöntemleri Tartışmalarınızın sonunda **args eklemek iyi bir alışkanlıktır).

+0

Teşekkür ederim, bunun böyle bir şey olacağını biliyordum ama bu işlevi çağırmadan gerekli argümanları aktarırken kafamı alamadım. functools öyle! Bu gece tekrar çalışacağım ve rapor vereceğim. – Horba