簡體   English   中英

Kivy 日期選擇器小工具

[英]Kivy Date Picker Widget

[已解決] 請參閱下面的已接受答案的應用程序和運行 kivy DatePicker 小部件的源代碼。

我一直在學習 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)) 

但只有最大遞歸錯誤。

解決方案:

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調用self.populate_body ,因此您會進入無限遞歸,僅被python遞歸限制停止。

您想要做的是綁定方法,但將date_cursor.day作為第一個參數,為此,來自functoolspartial函數是完美的。

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

創建一個新函數,就像 self.set_date 一樣,但將 date_cursor.day 作為第一個參數預加載。

編輯:另外,當你的部分函數被事件綁定調用時,它會收到其他參數,所以在你使用 ass 回調的函數/方法的參數末尾添加**args是一個好習慣(這里是set_date )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM