kivy - 添加标签到 IM/聊天屏幕 kivy
问题描述
我正在尝试在我的 kivy 应用程序中制作一个屏幕,两个用户可以在其中互相聊天,但我无法在屏幕上显示聊天消息。
大致目标示例:(向下滚动页面约 60% 以查看) https://medium.com/flutter-community/building-a-chat-app-with-flutter-and-firebase-从头开始 9eaa7f41782e
我已使用此答案将标签添加到屏幕的左侧(用户发送的消息): 标签一直在 ScrollView 屏幕 x 轴 Kivy 的边缘运行
但我现在正试图弄清楚如何在屏幕右侧添加标签(用户收到的消息)。我假设我需要一个GridLayout
有两列的,我需要先添加一个白色标签,然后再添加消息标签,然后它应该出现在右侧。我无法让标签尽可能地显示在屏幕上。
我也无法根据每个标签中的文本数量调整标签大小,我想我可能需要将每一行添加为新的GridLayout
肯定已经用 kivy 完成了类似的事情,并且有一个指南可以遵循,但我已经四处搜索,我能找到的只是老式的 UI 聊天屏幕设计。
.py 文件
import kivy
from kivymd.app import MDApp
from kivy.properties import ObjectProperty, StringProperty, NumericProperty, ListProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.core.text import Label as CoreLabel
from kivymd.uix.label import MDLabel
from kivymd.uix.button import MDFillRoundFlatButton, MDRoundFlatIconButton, MDRaisedButton, MDTextButton, MDIconButton
from kivy.core.window import Window
Window.size = (481, 600)
Window.clearcolor = (1,1,1,1)
class Chat(Screen):
chat_layout = ObjectProperty(None)
def send_message(self):
if self.ids.message.text:
lab1 = Label()
# calculate max allowable width in the GridLayout
max_width = self.chat_layout.width - self.chat_layout.spacing[0] - self.chat_layout.padding[0] - \
self.chat_layout.padding[2]
# specify font and font_size (so that the CoreLabel uses the same)
self.chat_layout.add_widget(
SmoothLabel.create_sized_label(text=self.ids.message.text, max_width=max_width, font_name='Roboto',
font_size=15))
self.chat_layout.add_widget(lab1)
self.ids.message.text = ""
else:
pass
def recv_message(self):
if self.ids.message.text:
# calculate max allowable width in the GridLayout
max_width = self.chat_layout.width - self.chat_layout.spacing[0] - self.chat_layout.padding[0] - \
self.chat_layout.padding[2]
# specify font and font_size (so that the CoreLabel uses the same)
chat_label = SmoothLabel.create_sized_label(text=self.ids.message.text, max_width=max_width, font_name='Roboto',
font_size=15)
lab1 = Label(width=max_width)
self.chat_layout.add_widget(lab1)
self.chat_layout.add_widget(chat_label)
self.ids.message.text = ""
else:
pass
class SmoothLabel(Label):
@staticmethod
def create_sized_label(**kwargs):
max_width = kwargs.pop('max_width', 0)
if max_width <= 0:
# just create a SmoothLabel without a text_size
return SmoothLabel(**kwargs)
# calculate what the SmoothLabel size will be
core_label = CoreLabel(padding=[10,10], **kwargs) # use same padding as SmoothLabel
core_label.refresh()
if core_label.width > max_width:
# width is too big, use text_size to force wrapping
return SmoothLabel(text_size=(max_width,None), **kwargs)
else:
# width is OK, no need for text_size
return SmoothLabel(**kwargs)
class WindowManager(ScreenManager):
pass
class MyApp(MDApp):
def build(self):
kv = Builder.load_file("kivy.kv")
self.sm = WindowManager()
screens = [Chat(name="chat")]
for screen in screens:
self.sm.add_widget(screen)
self.sm.current = "chat"
return self.sm
if __name__ == '__main__':
MyApp().run()
.kv 文件
<Chat>:
name: "chat"
chat_layout: chat_layout
GridLayout:
cols: 1
GridLayout:
cols: 2
id: chat_layout
padding: 15
GridLayout:
cols: 3
MDRaisedButton:
on_release: root.send_message()
text: "send message"
TextInput:
id: message
size_hint: None, None
size: 150,50
hint_text:
"Send message"
MDRaisedButton:
on_release: root.recv_message()
text: "receive message"
<SmoothLabel>:
size_hint: None, None
size: self.texture_size
padding: 10, 10
multiline: True
background_color: 0,0,0,0
background_normal: ""
back_color: 1,0,1,1
border_radius: [6]
canvas.before:
Color:
rgba: 0.2,0.6,1,1 #This changes the label colour
RoundedRectangle:
size: self.size
pos: self.pos
radius: self.border_radius
解决方案
BoxLayout
我认为您可以使用 a而不是 a来做您想做的事GridLayout
,并使用pos_hint
将聊天标签放在左侧或右侧:
import kivy
from kivymd.app import MDApp
from kivy.properties import ObjectProperty, StringProperty, NumericProperty, ListProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.core.text import Label as CoreLabel
from kivymd.uix.label import MDLabel
from kivymd.uix.button import MDFillRoundFlatButton, MDRoundFlatIconButton, MDRaisedButton, MDTextButton, MDIconButton
from kivy.core.window import Window
Window.size = (481, 600)
Window.clearcolor = (1,1,1,1)
class Chat(Screen):
chat_layout = ObjectProperty(None)
def send_message(self):
if self.ids.message.text:
# calculate max allowable width in the BoxLayout
max_width = (self.chat_layout.width - self.chat_layout.spacing - self.chat_layout.padding[0] - \
self.chat_layout.padding[2]) * 0.75
# specify font and font_size (so that the CoreLabel uses the same)
self.chat_layout.add_widget(
SmoothLabel.create_sized_label(text=self.ids.message.text, max_width=max_width, font_name='Roboto',
font_size=15, pos_hint={'x':0}))
self.ids.message.text = ""
self.ids.scroll.scroll_y = 0 # make sure last message is visible
else:
pass
def recv_message(self):
if self.ids.message.text:
# calculate max allowable width in the BoxLayout
max_width = (self.chat_layout.width - self.chat_layout.spacing - self.chat_layout.padding[0] - \
self.chat_layout.padding[2]) * 0.75
# specify font and font_size (so that the CoreLabel uses the same)
self.chat_layout.add_widget(
SmoothLabel.create_sized_label(text=self.ids.message.text, max_width=max_width, font_name='Roboto',
font_size=15, pos_hint={'right':1}))
self.ids.message.text = ""
self.ids.scroll.scroll_y = 0 # make sure last message is visible
else:
pass
class SmoothLabel(Label):
@staticmethod
def create_sized_label(**kwargs):
max_width = kwargs.pop('max_width', 0)
if max_width <= 0:
# just create a SmoothLabel without a text_size
return SmoothLabel(**kwargs)
# calculate what the SmoothLabel size will be
core_label = CoreLabel(padding=[10,10], **kwargs) # use same padding as SmoothLabel
core_label.refresh()
if core_label.width > max_width:
# width is too big, use text_size to force wrapping
return SmoothLabel(text_size=(max_width,None), **kwargs)
else:
# width is OK, no need for text_size
return SmoothLabel(**kwargs)
class WindowManager(ScreenManager):
pass
kv_str = '''
<Chat>:
name: "chat"
chat_layout: chat_layout
GridLayout:
cols: 1
ScrollView:
id: scroll
BoxLayout:
orientation: 'vertical'
id: chat_layout
padding: 15
spacing: 15
size_hint: 1, None
height: self.minimum_height
GridLayout:
cols: 3
MDRaisedButton:
on_release: root.send_message()
text: "send message"
TextInput:
id: message
size_hint: None, None
size: 150,50
hint_text:
"Send message"
MDRaisedButton:
on_release: root.recv_message()
text: "receive message"
<SmoothLabel>:
size_hint: None, None
size: self.texture_size
padding: 10, 10
multiline: True
background_color: 0,0,0,0
background_normal: ""
back_color: 1,0,1,1
border_radius: [6]
canvas.before:
Color:
rgba: 0.2,0.6,1,1 #This changes the label colour
RoundedRectangle:
size: self.size
pos: self.pos
radius: self.border_radius
'''
class MyApp(MDApp):
def build(self):
# kv = Builder.load_file("kivy.kv")
Builder.load_string(kv_str)
self.sm = WindowManager()
screens = [Chat(name="chat")]
for screen in screens:
self.sm.add_widget(screen)
self.sm.current = "chat"
return self.sm
if __name__ == '__main__':
MyApp().run()
我添加spacing
并消除了不再需要BoxLayout
的空。Labels
我使用Builder.load_string()
而不load_file()
只是为了我自己的方便。
推荐阅读
- ssh - 是否可以从 ovh 共享主机执行 ssh?
- python - `request.json()` 使用请求抛出“响应不可解释为 json”
- java - Java 8 SpringBoot HttpServletRequest 在 InputStream 中总是返回-1
- django - PermissionRequieredMixin 基于 django 视图的模板问题
- python-3.x - RandomForestRegressor 仅吐出 1 个预测
- java - Oracle Java 教程 [基本类 > 基本 I/O > 文件操作] 和 java.nio.file.Files 类 javadocs 差异
- r - R根据名称比较特定列
- r - 如何绘制历史数据和未来预测,以及预测的错误阴影
- android - 可在 Sceneform 和 ARCore 中渲染的 ShapeFactory 的不可见/透明材质
- python - 使用 Python randomQuizGenerator 错误自动化无聊的事情