无法更改 KivyMD 中的 InputBox 内容

Can't change an InputBox content in KivyMD

我正在尝试制作一个启动日期选择器的 InputBox,当您 select 一个日期时,它将出现在框中。所以我这样打结:

from kivymd.app import MDApp
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.menu import MDDropdownMenu
from kivy.metrics import dp
from kivymd.uix.snackbar import Snackbar
from kivymd.uix.dialog import MDDialog
from kivymd.uix.picker import MDDatePicker


class MainScreen(Screen):
    pass

class Predef(Screen):
    pass

class WindowManager(ScreenManager):
    pass



class MyApp(MDApp):
    def build(self):
        self.birthday = ''
        
        kv = Builder.load_file('file.kv')
        return kv
    

    def on_save(self, instance, value, date_range):
    
        print(value)
        self.birthday = value
        self.root.ids.input_box_date.text = self.birthday


    def on_cancel(self, instance, value):
        print("cancel")
    def date(self):
            date_dialog = MDDatePicker(
                title='Birthday',
                title_input= 'Birthday'
                )
            date_dialog.bind(on_save=self.on_save, on_cancel=self.on_cancel)
            date_dialog.open()
        
    
if __name__ == '__main__':
    MyApp().run()

这是 kv 文件中的代码:

WindowManager:
    MainScreen:
    Predef:
<MainScreen>:
    name: "main"
    MDBoxLayout:
        orientation: 'vertical'
        size: root.width, root.height
        MDToolbar:
            title: "App"
            left_action_items: [["menu", lambda x: side_bar.set_state("open")]]
        Label:
            text: 'Image'
            color: (0, 0, 0, 1)

        MDBottomAppBar:
            MDToolbar:
                icon: "botão.png"
                type: "bottom"
    MDNavigationDrawer:
        id: side_bar
        BoxLayout:
            orientation: 'vertical'
            padding: '16dp'
            Label:
                color: (0, 0, 0, 1)
                font_size: 35
                text: 'Settings      '
                size_hint_y: None
                height: self.texture_size[1]
                pos_hint: {'y': 0, 'left': 1}
            ScrollView:
                MDList:
                    OneLineListItem:
                        text: 'Predefitions'
                        on_release:
                            side_bar.set_state("close")
                            app.root.current = 'Predef'
                            root.manager.transition.direction = "up"
<Predef>:
    name: 'Predef'
    MDBoxLayout:
        orientation: 'vertical'
        size: root.height, root.width
        MDToolbar:
            title: "Predefinitions"
            left_action_items: [["menu", lambda x: bar.set_state("open")]]
            pos_hint: {'x': 0, 'top': 1}
        Label:
            color: (0, 0, 0, 1)
            text: 'Birthday'
        MDTextFieldRound:
            id: input_box_date    
            hint_text: "Birthday"
            text: app.birthday
            size_hint_x : 0.5
            pos_hint: {'center_x' : 0.5}
            on_focus: app.date()
        Label:
            text: ''
    MDNavigationDrawer:
        id: bar
        BoxLayout:
            orientation: 'vertical'
            padding: '16dp'
            Label:
                color: (0, 0, 0, 1)
                font_size: 35
                text: 'Settings      '
                size_hint_y: None
                height: self.texture_size[1]
                pos_hint: {'y': 0, 'left': 1}
            ScrollView:
                MDList:
                    OneLineListItem:
                        text: 'Main Screen'
                        on_release:
                            bar.set_state("close")
                            app.root.current = 'main'
                            root.manager.transition.direction = "up"     

启动时一切正常。 InputBox 如我所料开始为空,但是当我单击“确定”按钮时出现此错误:

'''
[INFO   ] [Base        ] Leaving application in progress...
 Traceback (most recent call last):
   File "kivy\properties.pyx", line 861, in kivy.properties.ObservableDict.__getattr__
 KeyError: 'input_box_date'
 
 During handling of the above exception, another exception occurred:
 
 Traceback (most recent call last):
   File "C:\Users\MYUSERNAME\AppData\Local\Programs\Python\Python39\program.py", line 112, in <module>
     MyApp().run()
   File "C:\Users\MYUSERNAME\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\app.py", line 950, in run
     runTouchApp()
   File "C:\Users\MYUSERNAME\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\base.py", line 582, in runTouchApp
     EventLoop.mainloop()
   File "C:\Users\MYUSERNAME\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\base.py", line 347, in mainloop
     self.idle()
   File "C:\Users\MYUSERNAME\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\base.py", line 391, in idle
     self.dispatch_input()
   File "C:\Users\MYUSERNAME\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\base.py", line 342, in dispatch_input
     post_dispatch_input(*pop(0))
   File "C:\Users\MYUSERNAME\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\base.py", line 308, in post_dispatch_input
     wid.dispatch('on_touch_up', me)
   File "kivy\_event.pyx", line 709, in kivy._event.EventDispatcher.dispatch
   File "C:\Users\MYUSERNAME\AppData\Local\Programs\Python\Python39\lib\site-packages\kivymd\uix\behaviors\ripple_behavior.py", line 296, in on_touch_up
     return super().on_touch_up(touch)
   File "C:\Users\MYUSERNAME\AppData\Local\Programs\Python\Python39\lib\site-packages\kivymd\uix\button.py", line 981, in on_touch_up
     return super().on_touch_up(touch)
   File "C:\Users\MYUSERNAME\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\uix\behaviors\button.py", line 179, in on_touch_up
     self.dispatch('on_release')
   File "kivy\_event.pyx", line 705, in kivy._event.EventDispatcher.dispatch
   File "kivy\_event.pyx", line 1248, in kivy._event.EventObservers.dispatch
   File "kivy\_event.pyx", line 1132, in kivy._event.EventObservers._dispatch
   File "C:\Users\MYUSERNAME\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 57, in custom_callback
     exec(__kvlang__.co_value, idmap)
   File "<string>", line 213, in <module>
   File "kivy\_event.pyx", line 705, in kivy._event.EventDispatcher.dispatch
   File "kivy\_event.pyx", line 1248, in kivy._event.EventObservers.dispatch
   File "kivy\_event.pyx", line 1172, in kivy._event.EventObservers._dispatch
   File "C:\Users\MYUSERNAME\AppData\Local\Programs\Python\Python39\program.py", line 77, in on_save
     self.root.ids.input_box_date.text = self.birthday
   File "kivy\properties.pyx", line 864, in kivy.properties.ObservableDict.__getattr__
 AttributeError: 'super' object has no attribute '__getattr__'
'''

我不知道为什么会出现此错误。我尝试用 self.root.ids.input_box_date.text = "string" 替换 self.root.ids.input_box_date.text = self.birthday,但没有任何变化。我该怎么办?

错误消息显示 KeyError: 'input_box_date'。这意味着您使用的 ids 中没有 input_box_date 键。该键在 <Predef>: 规则中定义,因此 id 将在 Predef 实例的 ids 中。解决方法是使用 Predef 实例访问 id。尝试替换:

self.root.ids.input_box_date.text = self.birthday

与:

self.root.get_screen('Predef').ids.input_box_date.text = self.birthday

TL;DR: 屏幕在 rootids 和 date-picker returns datetime.date 需要转换为 string for text-field: self.root.get_screen('Predef').ids.input_box_datex.text = str(value).

根和child仁

在您的 KV 文件中,您在 root WindowManager:

中定义了两个屏幕
WindowManager:
    MainScreen:
    Predef:

在您的 python 脚本中使用 self.root 访问此 root。 所以 print(self.root) 将给出类似的输出:

<main.WindowManager object at 0x7fa580c48f28>

在此根目录中,screens 可以使用 self.root.screens 作为索引列表找到。打印将输出:

[<Screen name='main'>, <Screen name='Predef'>]

按索引访问屏幕,例如第一次使用 screens[0] 或给定 id 的特定屏幕使用 get_screen(id).

屏幕上的所有 Kivy 小部件都具有 children: 所有这些 child 小部件都有 ids,可以使用 self.root.get_screen('Predef').ids 将其列为字典:

{'input_box_date': <WeakProxy to <kivymd.uix.textfield.MDTextFieldRound object at 0x7fc1aa8c9c88>>, 'bar': <WeakProxy to <kivymd.uix.navigationdrawer.MDNavigationDrawer object at 0x7fc1a9c9dc88>>}

并由 ids['input_box_date']ids.input_box_date 访问。

另请参阅:

设置日期 text-field

因为 text-field 是在 screen 内部定义的,id 为 'Predef',所以使用其中一个:

  • self.root.get_screen('Predef').ids['input_box_date']
  • self.root.get_screen('Predef').ids.input_box_date

但是 date-picker returns 类型的值 datetime 因此您需要使用 str():

将其转换为字符串
def on_save(self, instance, value, date_range):
    print("value/type:", value, type(value))
    self.birthday = value  # the instance variable becomes of type date
    self.root.get_screen('Predef').ids.input_box_date.text = str(date)  # convert to string

另请参阅:

访问树中的相关元素

print(self.root)
print(self.root.screens)
print(self.root.screens[1].ids)
print(self.root.screens[1].ids.input_box_date)
print(self.root.get_screen('Predef').children)
print(self.root.get_screen('Predef').ids['input_box_date'])
print(self.root.get_screen('Predef').ids.input_box_date)

参见: