为什么不在 __init__ 函数中创建小部件?
Why are widgets not created at __init__ function?
我是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
reference/object 但它可以从另一个相同的方法 class?
也许无法在 __init__
函数结束之前添加小部件,而我不会 know/understand?
所以,这是代码:
一个处理日期的小模块: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()
我不会尝试将代码缩减为示例,而是 post 一切,因为这样可能更好地理解问题出在哪里,并给我一些改进代码的提示。
Why does it seem that inside the init method I can't use add_widget for gridMonthView reference/object but it's possible from the other methods of the same class?
因为 self.gridMonthView 还没有在 __init__
中设置(即从默认值 None 修改)。这是一个技术限制 - 想象两个具有 kv 规则的小部件相互引用,在这种情况下,至少其中一个不能在其 __init__
中引用另一个,因为它将是第一个实际实例化的小部件.这就是您在这里看到的那种效果,必须先实例化所有小部件,然后才能设置它们之间的引用。
它适用于其他方法,因为您只能稍后调用它们,在所有实例化完成之后。
您可以使用 Clock.schedule_once(self.post_init, 0)
之类的东西,并将您的小部件添加到 post_init 方法中;间隔为 0 的调度确保它会在下一帧之前发生,但在当前正在进行的所有事情都完成之后。
我是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
reference/object 但它可以从另一个相同的方法 class?也许无法在
__init__
函数结束之前添加小部件,而我不会 know/understand?
所以,这是代码:
一个处理日期的小模块:
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()
我不会尝试将代码缩减为示例,而是 post 一切,因为这样可能更好地理解问题出在哪里,并给我一些改进代码的提示。
Why does it seem that inside the init method I can't use add_widget for gridMonthView reference/object but it's possible from the other methods of the same class?
因为 self.gridMonthView 还没有在 __init__
中设置(即从默认值 None 修改)。这是一个技术限制 - 想象两个具有 kv 规则的小部件相互引用,在这种情况下,至少其中一个不能在其 __init__
中引用另一个,因为它将是第一个实际实例化的小部件.这就是您在这里看到的那种效果,必须先实例化所有小部件,然后才能设置它们之间的引用。
它适用于其他方法,因为您只能稍后调用它们,在所有实例化完成之后。
您可以使用 Clock.schedule_once(self.post_init, 0)
之类的东西,并将您的小部件添加到 post_init 方法中;间隔为 0 的调度确保它会在下一帧之前发生,但在当前正在进行的所有事情都完成之后。