尝试实现加载/保存对话框,最终出现NoneType错误

时间:2014-12-11 17:50:15

标签: python kivy

所以我和我的朋友正在制作应用程序:

main.py:

from kivy.app import App
from kivy.lang import Builder
from kivy.factory import Factory

from kivy.uix.scrollview import ScrollView
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.textinput import TextInput
from kivy.uix.modalview import ModalView
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.accordion import Accordion, AccordionItem
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivy.uix.settings import SettingsWithSidebar
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup

from kivy.properties import ObjectProperty

from kivy.garden.navigationdrawer import NavigationDrawer

from settingsjson import general_settings

import os

Builder.load_file('main.kv')   # keep main.kv in the same directory


class MyDrop(DropDown):
    for i in range(5):
        print i

class LoadDialog(FloatLayout): 
    load = ObjectProperty(None)
    cancel = ObjectProperty(None)

class SaveDialog(FloatLayout):
    save = ObjectProperty(None)
    text_input = ObjectProperty(None)
    cancel = ObjectProperty(None)

class Notes(Screen, BoxLayout):
    top_layout = ObjectProperty(None)
    TextSpace = ObjectProperty(None)
    quick_settings = ObjectProperty(None)
    loadfile = ObjectProperty(None)
    savefile = ObjectProperty(None)
    text_input = ObjectProperty(None)

    def __init__(self, *args, **kwargs):
        super(Notes, self).__init__(*args, **kwargs)
        self.drop_down = MyDrop()

        dropdown = DropDown()
        notes = ["Notes", "Sketch", "To-do"]

        for note in notes:
            btn = Button(text='%r' % note, size_hint_y=None, height=40)
            btn.bind(on_release=lambda btn: dropdown.select(btn.text))
            dropdown.add_widget(btn)

        mainbutton = Button(text='Notes', size_hint=(1, 1))
        mainbutton.bind(on_release=dropdown.open)

        dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))

        self.top_layout.add_widget(mainbutton)

    def create_new_notebook(self):
        nnotebook = ModalView(size_hint=(None, None), size=(400, 60))
        box = BoxLayout(orientation='vertical')
        box.add_widget(Label(text='Name Your New Notebook'))
        notebookn = TextInput(focus='true', multiline='false')
        box.add_widget(notebookn)
        nnotebook.add_widget(box)
        nnotebook.open()
        nnotebook.bind(on_text_validate=self.ids.notebooks.add_widget(Button(text=str(notebookn.text))))  # declare the variable
        #return new_notebook

    def remove_notebook(self):
        new_notebook = self.create_new_notebook()
        self.ids.notebooks.remove_widget(new_notebook)  # remove the bottom button

    def dismiss_popup(self):
        self._popup.dismiss()

    def show_load(self):
        content = LoadDialog(load=self.load, cancel=self.dismiss_popup)
        self._popup = Popup(title="Load Note", content=content, size_hint=(0.9, 0.9))
        self._popup.open()

    def show_save(self):
        content = SaveDialog(save=self.save, cancel=self.dismiss_popup)
        self._popup = Popup(title="Save Note", content=content, size_hint=(0.9, 0.9))
        self._popup.open()

    def load(self, path, filename):
        with open(os.path.join(path, filename[0])) as stream:
            self.text_input.text = stream.read()

        self.dismiss_popup()

    def save(self, path, filename):
        with open(os.path.join(path, filename), 'w') as stream:
            stream.write(self.text_input.text)

        self.dismiss_popup()


sm = ScreenManager(transition=SlideTransition(direction='up'))

sm.add_widget(Notes(name='home'))

Factory.register('LoadDialog', cls=LoadDialog)
Factory.register('SaveDialog', cls=SaveDialog)

class MyApp(App):

    def build(self):
        self.settings_cls = SettingsWithSidebar
        return sm

    def build_config(self, config):
        config.setdefaults('General', {'Open_On_Startup': True})

    def build_settings(self, settings):
        settings.add_json_panel('General', self.config, data=general_settings)

if __name__ == '__main__':
    MyApp().run()

main.kv:

<Notes@BoxLayout>:
    top_layout: topLayout
    space_text: spacetext
    quick_settings: quicksettings
    text_input: text_input  

    orientation: "vertical" 
    BoxLayout:
        id: topLayout
        height: "40dp"
        size_hint_y: None
        pos_hint: {'top': 1}
        Button:
            text: "Settings"
            size_hint_x:0.1
            on_release: app.open_settings()  # root.manager.current = 'settings'
#       Button:
#           text: "Notes"
#           size_hint_x:0.9
#           on_release: root.drop_down.open(self)

    BoxLayout:
        padding: 0, 40
        id: spacetext
        NavigationDrawer:
            anim_type: 'reveal_below_simple'
            BoxLayout:
                orientation: 'vertical'
                Label:
                    size_hint_y: None
                    height: "30px"
                    text: 'MY NOTEBOOKS'

                BoxLayout:
                    id: notebooks
                    orientation: 'vertical'
                    Button:
                        text: 'Notebook 1'
                        min_height: '30px'  # this doesn't work but we somehow have to implement it
                    Button:
                        text: 'Notebook 2'
                    Button:
                        text: 'Notebook 3'

                BoxLayout:
                    id: notebook_mod
                    size_hint_y: None
                    height: '30px'

                    Button:
                        id: add_notebook_button
                        text: '+'
                        size_hint_y: None
                        height: '30px'
                        on_release: root.create_new_notebook()

                    Button:
                        id: remove_notebook_button
                        text: '-'
                        size_hint_y: None
                        height: '30px'
                        on_release: root.remove_notebook()

            Carousel:
                loop: False
                #size_hint_x: .85
                ScrollView:
                    id: scrlv
                    size_hint_x: 1
                    TextInput:
                        id: text_input
                            on_text:
                            size_hint: 1, None
                            height: max(self.minimum_height, scrlv.height)


    BoxLayout:
        id: quicksettings  # Quick settings menu (bold, italics, font-size, etc)
        height:'40dp'
        size_hint_y:None
        Button:
            markup: True
            text: ('[b][color=000000]B[/color][/b]')
        Button:
            markup: True
            text: ('[i][color=000000]I[/color][/i]')
        Button:
            markup: True
            text: ('[u][color=000000]U[/color][/u]')
        Button:
            text: 'Load'
            on_release: root.show_load()
        Button:
            text: 'Save'
            on_release: root.show_save()

<MyDrop>:
    Button:
        text: 'Notes'
        size_hint_y: None
        height: 40
        on_release: root.manager.current = 'home'
    Button:
        text: 'To-do'
        size_hint_y: None
        height: 40
        on_release: root.manager.current = 'todo'
    Button:
        text: 'Sketch'
        size_hint_y: None
        height: 40
        on_release: root.sm.current = 'sketch'

<LoadDialog>:
    BoxLayout:
        size: root.size
        pos: root.pos
        orientation: "vertical"
        FileChooserListView:
                id: filechooser

        BoxLayout:
                size_hint_y: None
                height: 30
                Button: 
                    text: "Cancel"
                    on_release: root.cancel()

                Button:
                    text: "Load"
                    on_release: root.load(filechooser.path, filechooser.selection)

<SaveDialog>:   
        text_input: text_input
    BoxLayout:
            size: root.size
            pos: root.pos
            orientation: "vertical"
            FileChooserListView:
                    id: filechooser
                on_selection: text_input.text = self.selection and self.selection[0] or ''

            TextInput:
                id: text_input
            size_hint_y: None
            height: 30
            multiline: False

            BoxLayout:
                size_hint_y: None
            height: 30
            Button:
                    text: "Cancel"
                    on_release: root.cancel()

            Button:
                    text: "Save"
                    on_release: root.save(filechooser.path, text_input.text)

这就是错误:

   File "main.py", line 26, in <module>
     Builder.load_file('main.kv')   # keep main.kv in the same directory
   File "/usr/lib/python2.7/site-packages/kivy/lang.py", line 1444, in load_file
     return self.load_string(data, **kwargs)
   File "/usr/lib/python2.7/site-packages/kivy/lang.py", line 1491, in load_string
     parser = Parser(content=string, filename=fn)
   File "/usr/lib/python2.7/site-packages/kivy/lang.py", line 1049, in __init__
     self.parse(content)
   File "/usr/lib/python2.7/site-packages/kivy/lang.py", line 1122, in parse
     objects, remaining_lines = self.parse_level(0, lines)
   File "/usr/lib/python2.7/site-packages/kivy/lang.py", line 1218, in parse_level
     level + 1, lines[i:], spaces)
   File "/usr/lib/python2.7/site-packages/kivy/lang.py", line 1218, in parse_level
     level + 1, lines[i:], spaces)
   File "/usr/lib/python2.7/site-packages/kivy/lang.py", line 1218, in parse_level
     level + 1, lines[i:], spaces)
   File "/usr/lib/python2.7/site-packages/kivy/lang.py", line 1218, in parse_level
     level + 1, lines[i:], spaces)
   File "/usr/lib/python2.7/site-packages/kivy/lang.py", line 1218, in parse_level
     level + 1, lines[i:], spaces)
   File "/usr/lib/python2.7/site-packages/kivy/lang.py", line 1271, in parse_level
     if current_property[:3] == 'on_':
 TypeError: 'NoneType' object has no attribute '__getitem__'

该应用程序基本上是一个笔记应用程序。 我尝试实现保存/加载对话框后出现此错误,该对话框是从文档中交叉复制的。 如果你有任何帮助, 谢谢!

2 个答案:

答案 0 :(得分:1)

您的kv代码中存在许多缩进问题 - 尽管这些问题可能只是复制/粘贴问题。但是,你的kv也有错误:

                TextInput:
                    id: text_input
                        on_text:
                        size_hint: 1, None
                        height: max(self.minimum_height, scrlv.height)

您有on_text:,但未指定任何处理程序。

答案 1 :(得分:0)

Kivy对缩进非常严格。间距必须是第一个缩进线上使用的空格数的倍数。上面的 main.kv 中的 LoadDialog 类中忽略了此规则。

项目的属性和元素也必须放在同一级别上。但是 SaveDialog 类的属性 text_input 比其子 BoxLayout 的缩进更多。

没有错误,只是解析器。