【问题标题】:KivyMD: AttributeError: 'NoneType' object has no attribute 'theme_cls' upon Adding MDToolbarKivyMD:AttributeError:“NoneType”对象在添加 MDToolbar 时没有属性“theme_cls”
【发布时间】:2019-11-13 22:42:19
【问题描述】:

我正在使用 KivyKivyMD,我正在尝试实现 MDToolbar。运行我的程序后,我收到此错误:AttributeError: 'NoneType' object has no attribute 'theme_cls'。我只包含了我的程序中的相关代码。在添加 MDToolbar 之前,一切都运行良好。我怎样才能让 MDToolbar 工作?请帮忙!

我的完整错误:

Parser: File "<inline>", line 22:
...
     20:<MDToolbar>
     21:    size_hint_y: None
>>   22:    height: root.theme_cls.standard_increment
     23:    padding: [root.theme_cls.horizontal_margins - dp(12), 0]
     24:    opposite_colors: True
...
AttributeError: 'NoneType' object has no attribute 'theme_cls'
  File "C:\Users\kelleym\AppData\Local\Continuum\anaconda3\lib\site-packages\kivy\lang\builder.py", line 696, in _apply_rule
    setattr(widget_set, key, value)
  File "kivy\weakproxy.pyx", line 35, in kivy.weakproxy.WeakProxy.__setattr__
  File "kivy\properties.pyx", line 497, in kivy.properties.Property.__set__
  File "kivy\properties.pyx", line 544, in kivy.properties.Property.set
  File "kivy\properties.pyx", line 599, in kivy.properties.Property.dispatch
  File "kivy\_event.pyx", line 1214, in kivy._event.EventObservers.dispatch
  File "kivy\_event.pyx", line 1120, in kivy._event.EventObservers._dispatch
  File "kivy\properties.pyx", line 1318, in kivy.properties.ReferenceListProperty.trigger_change
  File "kivy\properties.pyx", line 1333, in kivy.properties.ReferenceListProperty.trigger_change
  File "kivy\properties.pyx", line 599, in kivy.properties.Property.dispatch
  File "kivy\_event.pyx", line 1214, in kivy._event.EventObservers.dispatch
  File "kivy\_event.pyx", line 1120, in kivy._event.EventObservers._dispatch
  File "C:\Users\kelleym\AppData\Local\Continuum\anaconda3\lib\site-packages\kivymd\uix\behaviors\elevation.py", line 105, in _update_shadow
    self._shadow = App.get_running_app().theme_cls.quad_shadow
  File "C:\Users\kelleym\Desktop\Actual Inventory App\main.py", line 313, in <module>
    sm.add_widget(inventory(name='inventory'))

我的代码:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.theming import ThemeManager

Builder.load_string("""
<inventory>:
    NavigationLayout:
        id: "nav_layout"
        MDToolbar:
            title: "test"
        MDNavigationDrawer:
            drawer_logo: "test.png"
            id: "nav_drawer"
            NavigationDrawerSubheader:
                text: "[color=#black]Categories[/color]"
            NavigationDrawerIconButton:
                icon: 'printer'
                text: "Printers"
                on_release: root.manager.current = 'printers'
            NavigationDrawerIconButton:
                text: "PCs"
                icon: "laptop"
            NavigationDrawerIconButton:
                text: "Monitors"
                icon: "monitor"
            NavigationDrawerIconButton:
                text: "Tablets"
                icon: "tablet"
            NavigationDrawerIconButton:
                text: "Non-HP"
                icon: "close-circle-outline"
            NavigationDrawerIconButton:
                text: "Supplies"
                icon: "water"
            NavigationDrawerIconButton:
                text: "Misc."
                icon: "paperclip"
        Button:
            text: "test"
            on_release: app.nav_drawer.toggle()
""")


class inventory(BoxLayout, Screen):
    pass


sm = ScreenManager()
sm.add_widget(inventory(name='inventory'))


class TestApp(App):
    theme_cls = ThemeManager()

    def build(self):
        return sm


if __name__ == "__main__":
    TestApp().run()

【问题讨论】:

    标签: python kivy kivy-language


    【解决方案1】:

    此处的所有代码都适用于 Kivy 1.11.1KivyMD 0.102.0。 KivyMD 处于 alpha 状态,未来可以更改 API。

    1. build 函数中创建所有小部件。您应该移动 ScreenManager 的创建:
        def build(self):
            sm = ScreenManager()
            sm.add_widget(inventory(name='inventory'))
            return sm
    
    1. NavigationLayout 不能使用两个以上的小部件,其中一个是 MDNavigationDrawer,第二个是布局。创建BoxLayout并放入MDToolbarButton
        NavigationLayout:
            MDNavigationDrawer:
                # ...
                NavigationDrawerSubheader:
                    # ...
            BoxLayout:
                orientation: "vertical"
                MDToolbar:
                    title: "test"
                Button:
                    text: "test"
                    on_release: app.nav_drawer.toggle()
    
    1. kv 代码中的Id 属性应不带"":
        NavigationLayout:
            id: nav_layout
            MDNavigationDrawer:
                id: nav_drawer
    
    1. 要通过 id 调用小部件,您应该使用 app.root.ids.nav_drawer

    2. 要切换 NavigationDrawer,您应该调用 NavigationLayoutapp.root.ids.nav_layout.toggle_nav_drawer()

    3. 通常 NavigationLayout 用作根小部件。将 ScreenManager 添加到 BoxLayout

    4. 您可以使用 kv 代码将屏幕添加到 ScreenManager

            ScreenManager:
                id: screen_manager
    
                Inventory:
                    name: "inventory"
    
    1. 不要组合布局。不要写class Inventory(BoxLayout, Screen):。在屏幕内创建 BoxLayout
    <Inventory>:
        BoxLayout:
            orientation: "vertical"
    

    最终代码为:

    from kivy.app import App
    from kivy.lang import Builder
    from kivy.properties import ObjectProperty
    from kivy.uix.screenmanager import Screen
    from kivymd.theming import ThemeManager
    
    root_kv = """
    NavigationLayout:
        id: nav_layout
    
        MDNavigationDrawer:
            id: nav_drawer
            drawer_logo: "test.png"
    
            NavigationDrawerSubheader:
                text: "Categories"
            NavigationDrawerIconButton:
                text: "Printers"
                icon: "printer"
                on_release: app.screen_manager.current = "printers"
            NavigationDrawerIconButton:
                text: "PCs"
                icon: "laptop"
            NavigationDrawerIconButton:
                text: "Monitors"
                icon: "monitor"
            NavigationDrawerIconButton:
                text: "Tablets"
                icon: "tablet"
            NavigationDrawerIconButton:
                text: "Non-HP"
                icon: "close-circle-outline"
            NavigationDrawerIconButton:
                text: "Supplies"
                icon: "water"
            NavigationDrawerIconButton:
                text: "Misc."
                icon: "paperclip"
    
        BoxLayout:
            orientation: "vertical"
    
            ScreenManager:
                id: screen_manager
    
                Inventory:
                    name: "inventory"
    
    
    <Inventory>:
        BoxLayout:
            orientation: "vertical"
    
            MDToolbar:
                title: "test"
    
            Button:
                text: "test"
                on_release: app.root.toggle_nav_drawer()
    """
    
    
    class Inventory(Screen):
        pass
    
    
    class MainApp(App):
        theme_cls = ThemeManager()
        screen_manager = ObjectProperty()
    
        def build(self):
            self.root = Builder.load_string(root_kv)
            self.screen_manager = self.root.ids.screen_manager
    
    
    if __name__ == "__main__":
        MainApp().run()
    

    【讨论】:

      【解决方案2】:

      另一个有效的例子

      
      from kivy.lang import Builder
      from kivy.uix.boxlayout import BoxLayout
      from kivy.properties import StringProperty, ListProperty
      
      from kivymd.app import MDApp
      from kivymd.theming import ThemableBehavior
      from kivymd.uix.list import OneLineIconListItem, MDList
      
      KV = '''
      # Menu item in the DrawerList list.
      <ItemDrawer>:
          theme_text_color: "Custom"
          on_release: self.parent.set_color_item(self)
      
          IconLeftWidget:
              id: icon
              icon: root.icon
              theme_text_color: "Custom"
              text_color: root.text_color
      
      
      <ContentNavigationDrawer>:
          orientation: "vertical"
          padding: "8dp"
          spacing: "8dp"
      
          AnchorLayout:
              anchor_x: "left"
              size_hint_y: None
              height: avatar.height
      
              Image:
                  id: avatar
                  size_hint: None, None
                  size: "56dp", "56dp"
                  source: "data/logo/kivy-icon-256.png"
      
          MDLabel:
              text: "KivyMD library"
              font_style: "Button"
              size_hint_y: None
              height: self.texture_size[1]
      
          MDLabel:
              text: "kivydevelopment@gmail.com"
              font_style: "Caption"
              size_hint_y: None
              height: self.texture_size[1]
      
          ScrollView:
      
              DrawerList:
                  id: md_list
      
      
      
      Screen:
      
          MDNavigationLayout:
      
              ScreenManager:
      
                  Screen:
      
                      BoxLayout:
                          orientation: 'vertical'
      
                          MDToolbar:
                              title: "Navigation Drawer"
                              elevation: 10
                              left_action_items: [['menu', lambda x: nav_drawer.set_state("open")]]
      
                          Widget:
      
      
              MDNavigationDrawer:
                  id: nav_drawer
                  
                  ContentNavigationDrawer:
                      id: content_drawer
                      nav_drawer: nav_drawer
      '''
      
      
      class ContentNavigationDrawer(BoxLayout):
          pass
      
      
      class ItemDrawer(OneLineIconListItem):
          icon = StringProperty()
          text_color = ListProperty((0, 0, 0, 1))
      
      
      class DrawerList(ThemableBehavior, MDList):
          def set_color_item(self, instance_item):
              """Called when tap on a menu item."""
      
              # Set the color of the icon and text for the menu item.
              for item in self.children:
                  if item.text_color == self.theme_cls.primary_color:
                      item.text_color = self.theme_cls.text_color
                      break
              instance_item.text_color = self.theme_cls.primary_color
      
      
      class TestNavigationDrawer(MDApp):
          def build(self):
              return Builder.load_string(KV)
      
          def on_start(self):
              icons_item = {
                  "folder": "My files",
                  "account-multiple": "Shared with me",
                  "star": "Starred",
                  "history": "Recent",
                  "checkbox-marked": "Shared with me",
                  "upload": "Upload",
              }
              for icon_name in icons_item.keys():
                  self.root.ids.content_drawer.ids.md_list.add_widget(
                      ItemDrawer(icon=icon_name, text=icons_item[icon_name])
                  )
      
      
      TestNavigationDrawer().run()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多