Kivy MDBoxLayout 在 运行 时自动增加宽度,引发 [CRITICAL] [Clock] 警告

Kivy MDBoxLayout keeps increasing width automatically when running, raised [CRITICAL] [Clock] Warning

当我在我的应用程序中添加 ChatBubble 时,尽管 ChatBubble 的大小已经给定,但它会自动增加每毫秒的宽度。

命令提示符中显示的问题是

[CRITICAL] [Clock ] Warning, too much iteration done before the next frame. Check your code, or increase the Clock.max_iteration attribute

我试图找到一种方法让 ChatBubble 像 Messenger 或 Whatsapp 等任何其他聊天框一样正常工作,我也试图在我的代码中找到问题几个小时,但没有成功。任何帮助将不胜感激。

我把部分问题代码做了个小程序,方便大家看问题。

.py 文件

from kivy.lang import Builder
from kivy.properties import BooleanProperty, DictProperty, OptionProperty, StringProperty
from kivymd.app import MDApp 
#from components.label import PLabel
from kivymd.uix.boxlayout import MDBoxLayout, BoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.screenmanager import Screen
from kivy.uix.stacklayout import StackLayout
from kivy.uix.button import Button

class ChatBubble(MDBoxLayout):
    send_by_user = BooleanProperty()
    msg = StringProperty()
    time = StringProperty()

class Container(MDBoxLayout):
    def on_button_click(self):
        self.on_start()
    def on_start(self):
        self.c = ChatBubble()
        self.c.send_by_user = True
        self.c.msg = "hello world"
        self.c.time = "11:22AM"
        self.ids["lst"].add_widget(self.c)
        
class MainApp(MDApp):
    def build(self):
        self.root = Builder.load_file("chat_bubble.kv")

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

.kv 文件

Container:
 
<Container>:
    orientation: "vertical"
    ScrollView:
        MDList:
            id: lst
            spacing: 5
            padding: [0, 10, 0, 10]
    Button:
        text: "Click"
        on_press:
            root.on_button_click()

<ChatBubble>:
    id: chtbld
    md_bg_color: [0, 0, 0, 0]
    size_hint_y: None
    height: 60
    adaptive_height: True
    width: root.width
    padding: [10, 0, 10, 0]
    orientation: 'vertical'

    MDBoxLayout:
        height: msg_content.height + timed.height + 10
        width: msg_content.width + wid1.width + wid2.width
        size_hint: None, None
        pos_hint: {'right': 1} if chtbld.send_by_user == True else {'left': 1}
        radius: [10, 10, (1, -5), 10] if self.pos_hint == {'right': 1} else [10, 10, 10, (1, -5)]
        md_bg_color: app.theme_cls.primary_dark if root.send_by_user else app.theme_cls.primary_color
        Spacer:
            id: wid1
        MDBoxLayout:
            orientation: 'vertical'
            height: msg_content.height + tc.height + wid3.height
            width: msg_content.width

            MDLabel:
                id: msg_content
                text: root.msg
                width: tc.width if self.texture_size[0] < tc.width else self.texture_size[0]
                height: self.texture_size[1]
                size_hint_y: None
                text_size: chtbld.width-30 if self.width >= chtbld.width-30 else None, None
                halign: 'left'
                color: app.theme_cls.opposite_bg_normal

            MDBoxLayout:
                id: tc
                size_hint_y: None
                height: timed.height
                width: timed.width + 3
                spacing: 3
                MDLabel:
                    id: timed
                    text: root.time
                    size: self.texture_size
                    size_hint_y: None
                    font_size: 9
                    bold: True
                    halign: 'right'
                    text_size: None, None
                    color: [.8, .8, .8, 1]
            Spacer:
                id: wid3
                height: 5
        Spacer:
            id: wid2

<Spacer@Widget>:
    id: wid
    width: 5
    size_hint: None, None

这种行为通常意味着您的小部件的大小正在进入 inter-dependent 小部件大小的无限循环。您可以通过将 MDLabelwidth 计算更改为 msg_contentid 来自:

来停止该循环
width: tc.width if self.texture_size[0] < tc.width else self.texture_size[0]

至:

width: self.texture_size[0]

这可能不是您想要的,但似乎 msg_contenttc 的依赖导致了循环。

我认为问题是由于内部小部件的 inter-dependencies(尤其是 MDLabelid: msg_contentMDBoxLayoutid: tcMDLabelid: timed) 在 sizetexture_size 等字段中并且不单独处理这些属性。

在设置自定义 size 之前禁用 size_hint 似乎可行。

            ...
            MDBoxLayout:
                id: tc
                size_hint: None, None # To set custom size.
                height: timed.height
                width: timed.width + 3
                pos_hint: {'right': 1} # To hold itself and text on right.
                spacing: 3
                MDLabel:
                    id: timed
                    text: root.time
                    size_hint: None, None # To set custom size.
                    size: self.texture_size
                    font_size: 9
                    bold: True
                    halign: 'right' # This wouldn't work since its size is set to its texture_size.
                    ...

您还应该将 pos_hint 值更改为 {'left': 1}(这是一个无效密钥,可能 {"x" : 0} 就是您想要的)。


但是我发现你的设计有些过于复杂。 kivy 的一位核心开发人员 tshirtman 提供了一个示例 (messenger.py),您可以查看一下。