2012-12-04 11 views
6

[ĐÃ GIẢI PHÁP] Vui lòng xem bên dưới để áp dụng câu trả lời và mã nguồn được chấp nhận để hoạt động tiện ích DatePicker kivy.Tiện ích chọn ngày Kivy

Tôi đã học Kivy và quyết định đặt tiện ích con chọn ngày làm bài tập học tập.

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

Tôi đã nhấn một khối đường và không thể biết cách tiếp tục. Tôi muốn thêm một phương thức sao cho khi các date_labels được bấm, chúng đặt self.date thành một đối tượng ngày với phần ngày đó.

Tôi đã thử thêm

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

nhưng chỉ có lỗi đệ quy tối đa.

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

Ngoài ra, dưới dạng nhận xét vì nó không phải là câu hỏi của bạn, nhưng bạn không cần lưu trữ trong trường hợp của bạn nếu bạn không sử dụng giá trị sau, vì vậy trong populate_body, 'self.date_label' có thể được thay thế bằng chỉ' date_label' ở mọi nơi. Lưu ý phụ, xin hãy tôn trọng pep8: P, không có khoảng trống xung quanh '=' trong một cuộc gọi fonction, hai, và chỉ có hai dòng giữa mỗi định nghĩa lớp. có một ngày tốt đẹp :) chỉnh sửa: oh cũng cảm ơn vì đã chọn ngày cho kivy, tôi chắc chắn rằng nó có thể hữu ích cho người khác :) – Tshirtman

+0

Vâng, tôi đã trải qua một số lần lặp lại date_label và self.date_label và chỉ xảy ra để đăng trong biểu mẫu này. Tôi thấy hình đại diện của bạn ở khắp mọi nơi bằng cách này, bất cứ khi nào tôi tìm kiếm nội dung. Tôi đã bắt đầu nghĩ rằng đó là một loại avatar mặc định/meme! – Horba

+0

Hehe, tốt, tôi cố gắng trả lời tất cả các câu hỏi kivy ^^ – Tshirtman

Trả lời

3

bạn làm một sai lầm nhỏ trong ràng buộc, bạn gọi phương pháp này thay vì qua nó (do đó, bạn vượt qua là kết quả của self.set_date(date_cursor.day), nhưng gọi self.set_date cuộc gọi self.populate_body quá , vì vậy bạn nhận được trong một đệ quy vô hạn, chỉ dừng lại bởi giới hạn đệ quy python

Những gì bạn muốn làm là ràng buộc phương pháp nhưng với date_cursor.day làm tham số đầu tiên, cho điều này làChức năng, từ functools là hoàn hảo.

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

Tạo một fonction mới, đó là giống như self.set_date, nhưng với date_cursor.day cài đặt sẵn như một cuộc tranh luận đầu tiên.

chỉnh sửa: Ngoài ra, khi chức năng một phần của bạn được gọi bởi sự kiện ràng buộc, nó sẽ nhận được các đối số khác, vì vậy đó là một thói quen tốt để thêm **args vào cuối đối số của bạn trong các hàm/phương pháp bạn sử dụng ass callbacks (ở đây set_date).

+0

Cảm ơn bạn, tôi biết nó sẽ là một cái gì đó như thế nhưng không thể có được đầu của tôi xung quanh đi qua trong các đối số cần thiết mà không cần gọi chức năng. functools nó là! Tôi sẽ làm việc này một lần nữa tối nay và báo cáo lại. – Horba