嗨,我一直在try 用Kivy创建一个基本的聊天,并遵循了本教程的一部分: https://www.youtube.com/watch?v=lmWE2bydekk

新的消息被添加到底部,但我有一个问题,当用户滚动或添加下一条消息时,文本似乎从底部漂浮到顶部,在捕捉到底部后.我对视频中的原始代码做了一些修改,试图修复它,但无济于事.

完整代码:

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label  
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.uix.scrollview import ScrollView
from kivy.clock import Clock
          
Window.size = (500, 500)

class ScrollableLabel(ScrollView):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.layout = GridLayout(cols=1, size_hint_y=None)
        self.add_widget(self.layout)

        self.chat_history = Label(size_hint_y=None, markup=True, halign='left',text_size=(None, None))
        self.chat_history.bind(width=lambda s, w: s.setter('text_size')(s, (w, None)))

        self.scroll_to_point = Label(size_hint_y=None, height=1)

        self.layout.add_widget(self.chat_history)
        self.layout.add_widget(self.scroll_to_point)
    
    def update_chat_history(self, message):
        self.chat_history.text += '\n' + message
        self.chat_history.height = self.chat_history.texture_size[1]
        self.layout.height = self.chat_history.texture_size[1] +15
        self.chat_history.tet_size = (self.chat_history.width*0.98,None)

        self.scroll_to(self.scroll_to_point)
        #self.scroll_to_point.height = 1
        #self.scroll_y = 0
    
class Example(App):
    def build(self):
        layout = GridLayout(cols=1,  
                            row_default_height=40,
                            spacing = 10,
                            padding = 10,
                            )
        secondLayout = GridLayout(cols=2, row_force_default=True, row_default_height=40,
                            spacing = 10,
                            )
        self.new_message = TextInput(width=Window.size[0]*0.8,size_hint_x=None, multiline=False)
        submit = Button(text="submit", on_press=self.send_message)
        self.history = ScrollableLabel(height=Window.size[1]*0.9, size_hint_y=None)
        layout.add_widget(self.history)
        secondLayout.add_widget(self.new_message)
        secondLayout.add_widget(submit)
        layout.add_widget(secondLayout)

        initial_messages = ["Hello!", "How are you?", "Test message"]
        for message in initial_messages:
            self.incoming_message(message)
        Clock.schedule_once(self.focus_text_input, 1)

        layout.bind(size=self.adjust_fields)

        return layout
    
    def adjust_fields(self, *_):
        if Window.size[1]*0.1<50:
            new_height=Window.size[1]-50
        else:
            new_height=Window.size[1]*0.9
        self.history.height=new_height

        if Window.size[0]*0.2<160:
            new_width=Window.size[0]-160
        else:
            new_width=Window.size[0]*0.8
        self.new_message.width=new_width
    
    def send_message(self, _):
        message = self.new_message.text
        self.new_message.text=""
        if message:
            self.history.update_chat_history(f"[color=dd2020]You[/color] > {message}")
    
    def focus_text_input(self,_):
        self.new_message.focus = True

    def incoming_message(self, message):
        self.history.update_chat_history(f"[color=20dd20]PowerBot[/color] > {message}")
    
Example().run()

我试过的线路是self.scroll_to_point.height = 1self.scroll_y = 0,但我真的不知道我在做什么.有什么帮助吗?

推荐答案

我希望这会对你有所帮助.代码的基本概念是在ScrollView中放置一个标签,并在添加新消息时扩展标签的大小.这不是一个很实用的.有一个纹理大小的限制,虽然在这种情况下这不是问题,但更常见的是将小部件放在滚动视图下的布局中,而不仅仅是生长标签.

在下面的代码中,我创建了一个Message类,该消息被添加到ScrollView下的BoxLayout中.为了将文本定位在ScrollView的底部,我将Widget作为间隔符添加到BoxLayout中.使用KV简化了代码.它还"自动"处理绑定的设置,例如,每次添加小部件时都会设置高度.我使用的是BoxLayout,而不是带有单列的GridLayout.

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.core.window import Window

Window.size = (500, 500)

kv = """
<Message>:
    size_hint: 1, None
    text_size: self.width, None
    size: self.texture_size
    markup: True

BoxLayout:  # was layout
    orientation: 'vertical'
    padding: 10
    ScrollView:
        id: sv
        BoxLayout:
            id: chat
            spacing: 5
            padding: 10
            orientation: 'vertical'
            size_hint_y: None
            height: self.minimum_height
            Widget: # used as a spacer, push message to bottom
                size_hint_y: None
                height: sv.height
    BoxLayout:  # was second layout
        size_hint_y: None
        height: 40
        spacing: 10
        TextInput:
            id: ti
            multiline: False
            on_text_validate: app.send_message(self.text)
        Button:
            text: 'submit'
            size_hint_x: None
            width: 75
            on_release: app.send_message(ti.text)
"""


class Message(Label):
    pass


class ExampleApp(App):
    def build(self):
        return Builder.load_string(kv)

    def on_start(self):
        initial_messages = ["Hello!", "How are you?", "Test message"]
        for message in initial_messages:
            self.incoming_message(message)
        self.root.ids.sv.scroll_y = 0

    def send_message(self, message):
        self.root.ids.ti.text = ""
        if message:
            m = Message(text=f"[color=dd2020]You[/color] > {message}")
            self.root.ids.chat.add_widget(m)
            self.root.ids.ti.focus = True

    def incoming_message(self, message):
        m = Message(text=f"[color=20dd20]PowerBot[/color] > {message}")
        self.root.ids.chat.add_widget(m)
        self.root.ids.ti.focus = True


ExampleApp().run()

Python相关问答推荐

按日期和组增量计算总价值

是否有方法将现有的X-Y图转换为X-Y-Y1图(以重新填充)?

合并同名列,但一列为空,另一列包含值

inspect_asm不给出输出

将numpy矩阵映射到字符串矩阵

使用regex分析具有特定字符的字符串(如果它们存在)

Python中的函数中是否有充分的理由接受float而不接受int?

使用scipy. optimate.least_squares()用可变数量的参数匹配两条曲线

如何调整spaCy token 化器,以便在德国模型中将数字拆分为行末端的点

提取两行之间的标题的常规表达

Python 3.12中的通用[T]类方法隐式类型检索

使用Keras的线性回归参数估计

numba jitClass,记录类型为字符串

如何使用matplotlib在Python中使用规范化数据和原始t测试值创建组合热图?

Python库:可选地支持numpy类型,而不依赖于numpy

如何使用表达式将字符串解压缩到Polars DataFrame中的多个列中?

如何使用Pandas DataFrame按日期和项目汇总计数作为列标题

为什么np. exp(1000)给出溢出警告,而np. exp(—100000)没有给出下溢警告?

python中csv. Dictreader. fieldname的类型是什么?'

Discord.py -