我是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
函数prevMonth
和nextMonth
没有任何错误。
所以问题是:
为什么在__init__
方法中我似乎不能add_widget
用于gridMonthView
引用/对象,但是可以从同一个类的其他方法中使用它?
在__init__
函数结束我不了解/理解的内容之前,可能无法添加小部件吗?
所以,这是代码:
处理日期的小模块: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):
.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
应用的源代码: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()
我不会尝试将代码缩减为示例,而是发布所有内容,因为了解问题的位置可能会更好,并给我一些改进代码的提示。
答案 0 :(得分:0)
为什么在 init 方法中我似乎不能将add_widget用于gridMonthView引用/对象,但是可以从同一个类的其他方法中使用它?
因为尚未在__init__
内设置self.gridMonthView(即从默认值None修改)。这是一个技术限制 - 假设有两个小部件,其中kv规则相互引用,在这种情况下,至少有一个小部件无法在其__init__
中引用另一个,因为它将是第一个实际被实例化的小部件。这是你在这里看到的那种效果,必须先实例化小部件,然后才能设置它们之间的引用。
它适用于其他方法,因为在完成所有实例化后,您只能在以后调用它们。
您可以使用Clock.schedule_once(self.post_init, 0)
之类的内容,并将您的小部件添加到post_init方法中;间隔为0的调度确保它将在下一帧之前发生,但在当前正在进行的所有事情完成之后。