为什么在__init__函数中没有创建小部件?

时间:2015-11-10 00:34:44

标签: python kivy

我是kivy的新手所以我正在尝试为我学习这个框架做一个对我有用的应用程序。

我需要管理轮班工作时间表,以便开始将日历天插入GridLayout。经过几次麻烦后我被封锁了,因为我有这个错误:

File "turno.py", line 53, in load_content    
  self.gridMonthView.add_widget(DaysInfo(day=wid))  
AttributeError: 'NoneType' object has no attribute 'add_widget'

load_content函数内部调用__init__,当我尝试添加DaysInfo小部件时(当前月份的每一天都有一个),就会发生错误。

奇怪的(对我来说)行为是,如果我评论第n.47行(调用load_content方法)程序运行,然后我就可以从里面使用load_content函数prevMonthnextMonth没有任何错误。

所以问题是:

  • 为什么在__init__方法中我似乎不能add_widget用于gridMonthView引用/对象,但是可以从同一个类的其他方法中使用它?

  • __init__函数结束我不了解/理解的内容之前,可能无法添加小部件吗?

所以,这是代码:

  1. 处理日期的小模块:calendario.py

    from calendar import Calendar
    from datetime import date
    
    IT_months = ['Gennaio', 'Febbraio', 'Marzo', 'Aprile',\
                  'Maggio', 'Giugno', 'Luglio', 'Agosto',\
                  'Settembre', 'Ottobre', 'Novembre', 'Dicembre']
    
    IT_days = ['Lunedi',
               'Martedi',
               'Mercoledi',
               'Giovedi',
               'Venerdi',
               'Sabato',
               'Domenica']
    
    
    class Calendario():
    
        def __init__ (self):
    
            self.currDay = date.today()
            self.calen = Calendar(0)
            # def __init__ (self):
    
        def getMonth(self):
            return IT_months[self.currDay.month-1]
            # def getMonth(self):
    
        def getYear(self):
            return str(self.currDay.year)
            # def getYear(self):
    
        def getDaysOfMonth(self, listOfDays):
            listOfDays = []
            for td in self.calen.itermonthdates(self.currDay.year, self.currDay.month):
                listOfDays.append(td.day)
                # for td in ...
    
            return listOfDays
            # def getDaysOfMonth(self, listOfDays):
    
        def setNextMonth(self):
            if self.currDay.month == 12:
                self.currDay = self.currDay.replace(month=1, year=(self.currDay.year+1))
            else:
                self.currDay = self.currDay.replace(month=(self.currDay.month+1))
            # def setNextMonth(self):
    
        def setPrevMonth(self):
            if self.currDay.month == 1:
                self.currDay = self.currDay.replace(month=12, year=(self.currDay.year-1))
            else:
                self.currDay = self.currDay.replace(month=(self.currDay.month-1))
            # def setNextMonth(self):
    
  2. .kv文件:turno.kv

    #:kivy 1.9.0
    # 
    # menu bar
    #
    <MenuBar>:
        orientation: 'horizontal'
        padding: 1
        spacing: 1
        size_hint_y: 0.15
        Button:
            text: "Icon"
            size_hint_x: 0.3
            on_press: root.menu()
        Button:
            text: "Title"
            #size_hint: 1, 0.5
    
    
    #
    # day's info 
    #
    <DaysInfo>:
        orientation: 'vertical'
        padding: 1
        spacing: 1
        Label:
            color: 1,0,0,1
            background_color: 1,1,1,1
            id: f1
            text: " "
        Label:
            id: f2
            text: " "
        Label:
            id: f3
            text: " "
    
    
    #
    # month view
    #
    <MonthView>:
        gridMonthView: gridMonthView
        #
        orientation: "vertical"
        #
        # month selection
        #
        BoxLayout:
            id: box1
            orientation: 'horizontal'
            padding: 1
            spacing: 1
            size_hint_y: 0.15
            Button:
                backgroud_color: 0,1,0,1
                text: " << "
                size_hint_x: 0.1
                on_press: root.prevMonth()
            Button:
                id: idSelMonth
                text: root.curMonth
                size_hint_x: 0.5
            Button:
                id: isSelYear
                text: root.curYear
                size_hint_x: 0.3
            Button:
                text: " >> "
                size_hint_x: 0.1
                on_press: root.nextMonth()
        #
        # week's days
        #
        BoxLayout:
            id: box2
            orientation: 'horizontal'
            padding: 1
            spacing: 1
            color: 0., 0.5, 0.5, 1
            size_hint_y: 0.1
            Label:
                text: "Lu"
            Label:
                text: "Ma"
            Label:
                text: "Me"
            Label:
                text: "Gi"
            Label:
                text: "Ve"
            Label:
                text: "Sa"
            Label:
                text: "Do"
        #
        # Month's days
        #
        GridLayout:
            id: gridMonthView
            cols: 7
            rows: 6
            padding: 1
            spacing: 1
            size_hint_y: 0.6
    
    #
    # Turno Main Form
    #
    <TurnoMainForm>:
        orientation: 'vertical'
        padding: 20
        spacing: 10
        #width: 400
        #height: 800
    
        # menu bar
        MenuBar:
    
        # month view
        MonthView:
            id: id1
    
  3. 应用的源代码:turno.py

    # -*- coding: utf-8 -*-
    """
    Created on Mon Oct 06 12:25:04 2015
    
    @author: a809077
    """
    
    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout
    from kivy.uix.gridlayout import GridLayout
    from kivy.properties import ObjectProperty, StringProperty
    from kivy.config import Config
    
    from calendario import Calendario
    
    # impostazione della grandezza della finestra
    Config.set('graphics', 'width', '480')
    Config.set('graphics', 'height', '800')
    
    class MenuBar(BoxLayout):
    
        def __init__(self, **kwargs):
            super(MenuBar, self).__init__(**kwargs)
            print ("------- MenuBar -------")
            for child in self.children:
                print(child)
    
        def menu (self):
            print (" ====== click sul menu ======")
        # end of class: MenuBar(BoxLayout)
    
    ##
    ## visualizza i dati mensili    
    ##
    class MonthView(BoxLayout):
    
        gridMonthView = ObjectProperty(None)
    
        curMonth = StringProperty()
        curYear = StringProperty()
    
        def __init__(self, **kwargs):
            print ("------- Month View -------")
            self.curMonth = TurnoApp.currCal.getMonth()
            self.curYear = TurnoApp.currCal.getYear()
            super(MonthView, self).__init__(**kwargs)
            self.load_content(True)
            self.printInfo()
    
        def load_content(self, clearWidget = False):
            if (clearWidget):
                print "---- Clear Widgets ----"
                self.gridMonthView.clear_widgets()
    
            lod = list ()
            lod = TurnoApp.currCal.getDaysOfMonth(lod)
            for wid in lod:
                self.gridMonthView.add_widget(DaysInfo(day=wid))
    
        def prevMonth (self):
            print (" ====== click sul mese precedente 1 ======")
            TurnoApp.currCal.setPrevMonth()
            self.curMonth = TurnoApp.currCal.getMonth()
            self.curYear = TurnoApp.currCal.getYear()
            #self.printInfo()
            self.load_content(True)
    
        def nextMonth (self):
            print (" ====== click sul mese successivo ======")
            TurnoApp.currCal.setNextMonth()
            self.curMonth = TurnoApp.currCal.getMonth()
            self.curYear = TurnoApp.currCal.getYear()
            #self.printInfo()
            self.load_content(True)
    
        def printInfo (self):
            print " ____ items ____"
            for key, val in self.ids.items():
                print("key={0}, val={1}".format(key, val))
            print " ____ childs ____"
            for child in self.children:
                print("{} -> {}".format(child, child.id))
            print " ____ walk ____"
            for obj in self.walk():
                print obj
        # end of class: MonthView(GridLayout):
    
    
    class DaysInfo(BoxLayout):
         def __init__(self, **kwargs):
            super(DaysInfo, self).__init__()
            #print ("-- Days Info - {:d} ------".format(kwargs["day"]))
            self.ids["f1"].text =str(kwargs["day"])       
        # end of class: DaysInfo(BoxLayout):
    
    
    class TurnoMainForm(BoxLayout):
    
        def __init__(self, **kwargs):
            super(TurnoMainForm, self).__init__(**kwargs)
            print ("-------TurnoMainForm-------")
            for child in self.children:
                print(child)
        # end of class: TurnoMainForm(BoxLayout):
    
    
    class TurnoApp (App):
        # icon = 'mia_icona.png'
        title = 'Turno Terna'
        currCal = Calendario()
    
        def build (self):
            return TurnoMainForm()
            #return MonthView()
    
        # end of class: TurnoApp (App):
    
    
    TurnoApp().run()
    
  4. 我不会尝试将代码缩减为示例,而是发布所有内容,因为了解问题的位置可能会更好,并给我一些改进代码的提示。

1 个答案:

答案 0 :(得分:0)

  

为什么在 init 方法中我似乎不能将add_widget用于gridMonthView引用/对象,但是可以从同一个类的其他方法中使用它?

因为尚未在__init__内设置self.gridMonthView(即从默认值None修改)。这是一个技术限制 - 假设有两个小部件,其中kv规则相互引用,在这种情况下,至少有一个小部件无法在其__init__中引用另一个,因为它将是第一个实际被实例化的小部件。这是你在这里看到的那种效果,必须先实例化小部件,然后才能设置它们之间的引用。

它适用于其他方法,因为在完成所有实例化后,您只能在以后调用它们。

您可以使用Clock.schedule_once(self.post_init, 0)之类的内容,并将您的小部件添加到post_init方法中;间隔为0的调度确保它将在下一帧之前发生,但在当前正在进行的所有事情完成之后。