在本教程中,我们将使用Flet framework在Python中使用Flutter UI创建一个微不足道的内存聊天应用程序。该应用程序可能是创建自己更复杂和有用的项目的好起点。
在本教程中,您将学习如何:
- Create your first Flet app
- Add page controls and handle events
- Broadcast messages using built-in PubSub library
- Use AlertDialog control for accepting user name
- Enhance user interface with re-usable controls
- Deploy the app as a web app
完整的应用程序看起来像这样:
您可以使用现场演示here。
可以找到聊天应用程序的完整代码。
Flet入门
要创建一个Flet Web应用程序,您不需要了解HTML,CSS或JavaScript,但是您确实需要对Python和面向对象的编程的基本知识。
flet需要python 3.7或更高。要在Python中创建Flet应用程序,您需要先安装flet
模块:
pip install flet
注意:升级flet
升级flet
模块,运行:pip install flet --upgrade
创建带有以下内容的hello.py
:
import flet as ft
def main(page: ft.Page):
page.add(ft.Text(value="Hello, world!"))
ft.app(target=main)
运行此应用程序,您将看到一个带有问候的新窗口:
添加页面控件和处理活动
开始,我们希望能够获取用户输入(聊天消息)并在屏幕上显示消息历史记录。此步骤的布局看起来像这样:
要实现此布局,我们将使用这些Flet控件:
-
koude4-一个容器垂直显示聊天消息(
Text
控件)。 - koude5-聊天中显示的聊天消息。
- koude8-用于从用户获取新消息输入的输入控件。
-
koude9-“发送”按钮将添加新消息到chat
Column
。 -
koude11-一个水平显示
TextField
和ElevatedButton
的容器。
创建带有以下内容的chat.py
:
import flet as ft
def main(page: ft.Page):
chat = ft.Column()
new_message = ft.TextField()
def send_click(e):
chat.controls.append(ft.Text(new_message.value))
new_message.value = ""
page.update()
page.add(
chat, ft.Row(controls=[new_message, ft.ElevatedButton("Send", on_click=send_click)])
)
ft.app("chat", target=main, view=ft.WEB_BROWSER)
当用户单击“发送”按钮时,它会触发调用send_click
方法的on_click
事件。然后,send_click
将新的Text
控件添加到列controls
列表中,并清除new_message
textfield值。
重要
更新控件的任何属性后,应要求对控件的update()
方法(或其父控件)进行更新。
聊天应用现在看起来像这样:
广播聊天消息
在上一步中,我们创建了一个简单的Web应用程序,该应用程序从用户中获取输入并在屏幕上显示聊天消息。如果您在两个Web浏览器选项卡中打开此应用程序,它将创建两个应用程序会话。每个会话都会有自己的消息列表。
要构建实时聊天应用程序,您需要以某种方式传递聊天应用程序会话之间的消息。当用户发送消息时,应将其广播到所有其他应用程序会话并在其页面上显示。
flet提供了一种简单的内置PubSub在页面之间的异步通信的机制。
首先,我们需要订阅用户接收广播消息:
page.pubsub.subscribe(on_message)
pubsub.subsribe()
方法将将当前的应用程序会话添加到订户列表中。它接受handler
作为一个参数,后来将在发布者调用pubsub.send_all()
方法的那一刻被调用。
在handler
中,我们将在chat controls
列表中添加新消息(Text
):
def on_message(message: Message):
chat.controls.append(ft.Text(f"{message.user}: {message.text}"))
page.update()
最后,当用户单击“发送”按钮时,您需要调用pubsub.send_all()
方法:
def send_click(e):
page.pubsub.send_all(Message(user=page.session_id, text=new_message.value))
new_message.value = ""
page.update()
page.add(chat, ft.Row([new_message, ft.ElevatedButton("Send", on_click=send_click)]))
pubsub.send_all()
将调用on_message()
并将消息对象传递给它。
这是此步骤的完整代码:
import flet as ft
class Message():
def __init__(self, user: str, text: str):
self.user = user
self.text = text
def main(page: ft.Page):
chat = ft.Column()
new_message = ft.TextField()
def on_message(message: Message):
chat.controls.append(ft.Text(f"{message.user}: {message.text}"))
page.update()
page.pubsub.subscribe(on_message)
def send_click(e):
page.pubsub.send_all(Message(user=page.session_id, text=new_message.value))
new_message.value = ""
page.update()
page.add(chat, ft.Row([new_message, ft.ElevatedButton("Send", on_click=send_click)]))
ft.app(target=main, view=ft.WEB_BROWSER)
用户名对话框
您在上一步中创建的聊天应用程序具有在用户会话之间交换消息所需的基本功能。不过,它不是很友好的,因为它显示了发送消息的session_id
,这并没有说明与您交流的人。
让我们改进我们的应用程序以显示每个消息的用户名而不是session_id
。要捕获用户名,我们将使用koude33控件。让我们添加到页面:
user_name = ft.TextField(label="Enter your name")
page.dialog = ft.AlertDialog(
open=True,
modal=True,
title=ft.Text("Welcome!"),
content=ft.Column([user_name], tight=True),
actions=[ft.ElevatedButton(text="Join chat", on_click=join_click)],
actions_alignment="end",
)
注意
,将在程序开始时打开对话框。
由于我们已将其open
属性设置为True
。
用户单击“加入聊天”按钮时,它将调用join_click
方法,该方法应向所有订户发送消息,并通知他们用户已加入聊天。此消息应该与常规聊天消息不同,例如:
让我们将message_type
属性添加到Message
类中以区分登录和聊天消息:
class Message():
def __init__(self, user: str, text: str, message_type: str):
self.user = user
self.text = text
self.message_type = message_type
我们将在on_message
方法中检查message_type
:
def on_message(message: Message):
if message.message_type == "chat_message":
chat.controls.append(ft.Text(f"{message.user}: {message.text}"))
elif message.message_type == "login_message":
chat.controls.append(
ft.Text(message.text, italic=True, color=ft.colors.BLACK45, size=12)
)
page.update()
“ login_message”和“ chat_message”类型的消息现在将在两个事件上发送:当用户加入聊天和用户发送消息时。
让我们创建join_click
方法:
def join_click(e):
if not user_name.value:
user_name.error_text = "Name cannot be blank!"
user_name.update()
else:
page.session.set("user_name", user_name.value)
page.dialog.open = False
page.pubsub.send_all(Message(user=user_name.value, text=f"{user_name.value} has joined the chat.", message_type="login_message"))
page.update()
我们使用page session storage存储User_name将其未来用途存储在send_click
方法中发送聊天消息。
注意
用户名对话框将在我们将其open
属性设置为False
并致电update()
方法后立即关闭。
最后,让我们更新send_click
方法使用以前使用page.session
保存的user_name
:
def send_click(e):
page.pubsub.send_all(Message(user=page.session.get('user_name'), text=new_message.value, message_type="chat_message"))
new_message.value = ""
page.update()
可以找到此步骤的完整代码here。
增强用户界面
您在上一步中创建的聊天应用程序已经达到了其在用户之间具有基本登录功能的用户之间的目的。
在转到deploying your app之前,我们建议在其中添加一些额外功能,以改善用户体验并使应用程序看起来更专业。
可重复使用的用户控件
您可能想以不同的格式显示消息:
聊天消息现在将是包含用户名缩写的koude50的Row
和包含两个Text
控件的Column
:用户名和消息文本。
我们需要在聊天应用程序中显示很多聊天消息,因此创建自己的可重复使用的控件是有意义的。让我们创建一个将从Row
继承的新的ChatMessage
类。
创建ChatMessage
类实例时,我们将通过一个参数传递Message
对象,然后ChatMessage
将根据message.user_name
和message.text
显示自身显示:
class ChatMessage(ft.Row):
def __init__(self, message: Message):
super().__init__()
self.vertical_alignment="start"
self.controls=[
ft.CircleAvatar(
content=ft.Text(self.get_initials(message.user_name)),
color=ft.colors.WHITE,
bgcolor=self.get_avatar_color(message.user_name),
),
ft.Column(
[
ft.Text(message.user_name, weight="bold"),
ft.Text(message.text, selectable=True),
],
tight=True,
spacing=5,
),
]
def get_initials(self, user_name: str):
return user_name[:1].capitalize()
def get_avatar_color(self, user_name: str):
colors_lookup = [
ft.colors.AMBER,
ft.colors.BLUE,
ft.colors.BROWN,
ft.colors.CYAN,
ft.colors.GREEN,
ft.colors.INDIGO,
ft.colors.LIME,
ft.colors.ORANGE,
ft.colors.PINK,
ft.colors.PURPLE,
ft.colors.RED,
ft.colors.TEAL,
ft.colors.YELLOW,
]
return colors_lookup[hash(user_name) % len(colors_lookup)]
ChatMessage
控件提取缩写和算法从用户名衍生出头像。
稍后,如果您决定改善控制布局或其逻辑,它不会影响程序的其余部分 - 这就是封装的力量!
布置控件
现在,您可以使用全新的ChatMessage
为聊天应用构建更好的布局:
将创建ChatMessage
的实例,而不是在on_message
中的普通Text
聊天消息:
def on_message(message: Message):
if message.message_type == "chat_message":
m = ChatMessage(message)
elif message.message_type == "login_message":
m = ft.Text(message.text, italic=True, color=ft.colors.BLACK45, size=12)
chat.controls.append(m)
page.update()
新布局建议的其他改进是:
-
koude65而不是用于显示消息的
Column
,以便稍后浏览消息 -
Container
用于displayng边界围绕ListView
-
koude69而不是
ElevatedButton
发送消息 - 使用koude71属性进行控件填充可用空间
这是您可以实现此布局的方式:
# Chat messages
chat = ft.ListView(
expand=True,
spacing=10,
auto_scroll=True,
)
# A new message entry form
new_message = ft.TextField(
hint_text="Write a message...",
autofocus=True,
shift_enter=True,
min_lines=1,
max_lines=5,
filled=True,
expand=True,
on_submit=send_message_click,
)
# Add everything to the page
page.add(
ft.Container(
content=chat,
border=ft.border.all(1, ft.colors.OUTLINE),
border_radius=5,
padding=10,
expand=True,
),
ft.Row(
[
new_message,
ft.IconButton(
icon=ft.icons.SEND_ROUNDED,
tooltip="Send message",
on_click=send_message_click,
),
]
),
)
可以找到此步骤的完整代码。
这是本教程目的的聊天应用程序的最终版本。您可以在下面阅读有关我们所做的增强功能的更多信息。
键盘支持
聚焦输入控件
所有数据输入控件都具有autofocus
属性,将其设置为True
时,将初始焦点移至控件。如果带有autofocus
集的页面上有多个控件,则添加到页面的第一个将获得焦点。
我们在对话框内部的用户名Textfield上设置了autofocus=True
,然后在Textfield上设置了聊天消息,以在对话框关闭时将其设置为初始焦点。
用户单击“发送”按钮或按Enters提交聊天消息时,Textfield失去了焦点。
为了编程设置控制焦点,我们使用了koude76方法。
在Enter
上提交表格
,只需在键盘上按下Enter
按钮即可提交表格!在对话框中键入您的名字,点击Enter
,键入新消息,点击Enter
,键入另一个,键入Enter
-根本不涉及鼠标! ð
flet可以通过提供koude82事件处理程序来支持,该事件处理程序在用户按Enter
按钮时发射焦点。
输入多行消息
多行文本菲尔德又如何将光标推向下一行?我们也涵盖了! TextField
控件具有koude86属性,将其设置为True
时,启用类似Discord的行为:到达新线路用户时按Shift
+Enter
,同时击中Enter
时会提交表单。
动画滚动到最后一条消息
注意到滚动到聊天窗口中的最后一条消息的好动画吗?可以通过将koude91属性设置为True
来启用。最高的Page
类是可滚动容器本身,也支持koude94。
页面标题
最终触摸 - 可以简单地更改为:
的页面标题
page.title = "Flet Chat"
page.update()
部署应用程序
恭喜!您已经用Flet创建了python的聊天应用程序,看起来很棒!
现在是时候与世界分享您的应用程序了!
Follow these instructions将您的flet应用程序部署为fly.io或reveit的Web应用程序。
下一步是什么
我们可以实现许多功能来改进此聊天应用程序:
- 断开,重新连接,会话超时
- 上传/下载图像
- 身份验证,头像
- 使用数据库进行存储
- 聊天频道,主题
- 全文搜索
- 表情符号,Markdown
- 机器人
- 移动应用
如果您想为应用程序/教程做出贡献并与其他Flet开发人员分享。
概括
在本教程中,您学会了如何:
- 创建一个简单的flet应用;
- 添加页面控件和处理事件;
- 使用PubSub库中的使用;
- 输入用户名的用户alertdialog;
- 使用可重复使用的控件构建页面布局;
- 将您的Flet应用程序部署到网络;
要进一步阅读,您可以探索controls和examples repository。