【问题标题】:Kivy add widgets on different sides of the LayoutKivy 在布局的不同侧添加小部件
【发布时间】:2018-02-22 09:16:42
【问题描述】:

我有一个聊天应用程序,它使用小部件来打印消息。我想在不同的面打印这些,所以用户输入在右边,答案在左边。此外,我希望聊天框滚动到新消息。这是我的代码,我尝试使用 StackLayout,却发现它不起作用:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder

class Message(Widget):
    pass

class KatApp(App):
    def post(self):
        msg = self.root.ids.usrinp.text
        if len(msg) > 0:
            self.root.ids.chatbox.orientation = 'tb-rl'
            msgbox = Message()
            msgbox.ids.mlab.text = msg
            self.root.ids.chatbox.add_widget(msgbox)
            self.root.ids.scrlv.scroll_to(msgbox)
            self.root.ids.usrinp.text = ''
    def resp(self,msg):
        if len(msg) > 0:
            ansr = msg
            self.root.ids.chatbox.orientation = 'tb-lr'
            ansrbox = Message()
            ansrbox.ids.mlab.text = str(ansr)
            self.root.ids.chatbox.add_widget(ansrbox)
            self.root.ids.scrlv.scroll_to(ansrbox)
            self.root.ids.usrinp.text = ''

    def build(self):
        return Builder.load_string('''
<Message@Widget>:
    size_hint: None, None
    height: mlab.height
    width: mlab.width
    canvas:
        Color:
            rgba: 0, 1, 0, 0.7
        Rectangle:
            pos: self.pos
            size: self.size
    Label:
        id: mlab
        center: root.center
        padding: 10, 10
        markup: True
        text_size: (None, None)
        text: ''
        haligh: 'left'
        valign: 'top'
        size_hint: (1, None)
        size: self.texture_size
        color: 0, 0, 0

ScreenManager:
    Screen:

        BoxLayout:
            orientation: 'vertical'

            ScrollView:

                canvas.before:
                    Color:
                        rgb: 1, 1, 1
                    Rectangle:
                        pos: self.pos
                        size: self.size

                StackLayout:
                    id: chatbox
                    padding: 10, 10
                    orientation: 'tb-rl'

            BoxLayout:
                orientation: 'horizontal'
                padding: 10, 10, 10, 10
                size_hint: 1, None
                height: 50

                BoxLayout:
                    id: inpbox
                    height: max(40, scrlv.height)
                    size_hint: 0.9, None

                    ScrollView:
                        id: scrlv
                        width: inpbox.width - 15
                        x: inpbox.x + 10
                        y: inpbox.y
                        height: 
                            (len(usrinp._lines)+1) * usrinp.line_height - 5 \
                            if (len(usrinp._lines)+1 <= 5) \
                            else 5 * usrinp.line_height - 5

                        TextInput:
                            id: usrinp
                            valign: 'middle'
                            halign: 'left'
                            font_size: 16
                            multiline: True
                            size_hint: scrlv.size_hint_x, None
                            padding: 10, 0, 10, 0


                Button:
                    id: post
                    border: 0, 0, 0, 0
                    size: 40, 40
                    size_hint: None, None
                    on_press:
                        root.inp = usrinp.text
                        app.post()
                    on_release:
                        app.resp(root.inp)
''')

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

就本示例而言,右下角的按钮发送用户输入 on_press 并使用相同的输入 on_release 进行回答。

另外,是否可以为消息小部件设置最大宽度,例如,如果它到达页面中间,它应该在下一行?

我很难弄清楚的另一件事是 TextInput。似乎,使用多行选项,当一个单词足够长到下一行并且我尝试删除它时,会保留一些空间并且它会阻止框调整大小。要重现这一点,只需键入“aaaaaaaaaa”,直到它位于第 3 行,然后尝试将其删除。

【问题讨论】:

    标签: python kivy


    【解决方案1】:

    要包裹小部件的宽度,试试这个:

    读取文本和创建标签的功能

      def Sender_chat_bubble():
    

    测量展开后文本的长度

        Measure = Label(text=self.chatinputfield.text)
        Measure.texture_update()
    
        if Measure.texture_size[0]== 0 or self.chatinputfield.text=='':
            return 0
    

    如果文本不长,我添加的填充保持相同的宽度 + 10

        elif Measure.texture_size[0]<250:
            xsize = Measure.texture_size[0] 
            chatbubble = ChatBubble_Send(text=self.chatinputfield.text, width=xsize+10, padding_y=10, padding_x=10)
        
    

    如果展开的文本比您的限制长(此处为 250),让我们将其包装为 260(250 + 10 填充)

    else:
         chatbubble = ChatBubble_Send(text=self.chatinputfield.text, width=250+10, padding_y=10, padding_x=10)
    

    为标签制作颜色的类

    class ColorLabelSEND(Label):
        bgcolor = ListProperty([0.7, 0.7, 0.7, 0.7])
        def __init__(self, **kwargs):
            super(ColorLabelSEND, self).__init__(**kwargs)
            with self.canvas.before:
                r, g, b, a = self.bgcolor
                Color(r, g, b, a)
                self.rect = Rectangle(
                                size=self.size,
                                pos=self.pos)
                self.bind(size=self._update_rect,
                          pos=self._update_rect)
    
        def _update_rect(self, instance, value):
            self.rect.pos = instance.pos
            self.rect.size = instance.size
    

    用于包装文本和标签的类

    class ChatBubble_Send(ColorLabelSEND):
    
        def __init__(self, **kwargs):
            super(ChatBubble_Send, self).__init__(**kwargs)
            self.size_hint = (None, None)
    
            #Constrain horizontally to size of label and free vertically
            self.text_size = (self.width, None) 
            self.width = self.width + 15
    
        def on_texture_size(self,*args):
           self.texture_update()
           self.height = self.texture_size[1]
    

    【讨论】:

    • 我已经有 2 年没有看过这个项目了,但我认为新的 Kivy 版本让这件事变得更简单了。我不确定它的效果如何,但我会将其标记为答案,以防人们将来搜索它。感谢您回答这么老的问题!
    • 不客气!我也在制作一个聊天应用程序,对我来说它工作正常。我还没有从 kivy 或 kivyMD 看到这样的功能,所以我仍在使用相同的功能。在 Windows 和 MacOS 上它工作正常,但我注意到在 android 上,文本以随机方式从标签中消失。
    【解决方案2】:

    可以使用 BoxLayout 来完成每一面的书写。

    def post(self):
        msg = self.root.ids.usrinp.text
        if len(msg) > 0:
            msgbox = Message()
            msgbox.ids.mlab.text = msg
            msgbox.pos_hint = {'right': 1}
            self.root.ids.chatbox.add_widget(msgbox)
            self.root.ids.scrlv.scroll_to(msgbox)
            self.root.ids.usrinp.text = ''
    
    def resp(self, msg):
        if len(msg) > 0:
            ansr = msg
            ansrbox = Message()
            ansrbox.ids.mlab.text = str(ansr)
            ansrbox.pos_hint = {'x': 0}
            self.root.ids.chatbox.add_widget(ansrbox)
            self.root.ids.scrlv.scroll_to(ansrbox)
            self.root.ids.usrinp.text = ''
    

    在构建器中:

            ScrollView:
    
                canvas.before:
                    Color:
                        rgb: 1, 1, 1
                    Rectangle:
                        pos: self.pos
                        size: self.size
    
                BoxLayout:
                    orientation: 'vertical'
                    id: chatbox
                    padding: 10, 10
                    spacing: 5
    

    pos_hint: {'right': 1} 添加到输入小部件后,文本现在位于右侧,如下所示:

    现在问题仍然存在于小部件的宽度上:

    我尝试将小部件的宽度设置为max(root.width, mlab.width),但它不起作用。另外,现在,向上滚动不起作用。

    【讨论】:

      猜你喜欢
      • 2016-04-13
      • 2012-09-20
      • 1970-01-01
      • 2014-10-17
      • 1970-01-01
      • 2023-03-20
      • 2021-10-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多