Python使用Flet打造跨平臺(tái)文本編輯器
在Python生態(tài)中,構(gòu)建圖形界面應(yīng)用常面臨兩難選擇:傳統(tǒng)GUI庫(kù)(如Tkinter)開(kāi)發(fā)效率低,跨平臺(tái)框架(如Kivy)學(xué)習(xí)曲線陡峭。Flet框架的出現(xiàn)打破了這一僵局——它基于Flutter引擎,卻用Python作為開(kāi)發(fā)語(yǔ)言,讓開(kāi)發(fā)者既能享受Flutter的現(xiàn)代化UI能力,又無(wú)需掌握Dart語(yǔ)言。本文將通過(guò)實(shí)戰(zhàn)案例,手把手教你用Flet開(kāi)發(fā)一個(gè)支持自動(dòng)保存、多端適配的文本編輯器,代碼量不足200行,卻能實(shí)現(xiàn)專業(yè)級(jí)功能。
一、環(huán)境搭建:3分鐘啟動(dòng)開(kāi)發(fā)
1.1 安裝Flet
Flet的安裝過(guò)程堪稱"傻瓜式"操作。在終端輸入以下命令即可完成核心庫(kù)安裝:
pip install flet
對(duì)于需要打包應(yīng)用的開(kāi)發(fā)者,建議額外安裝Flutter SDK以獲得完整功能支持。不過(guò)Flet已內(nèi)置了Flutter運(yùn)行時(shí),即使不安裝SDK也能直接開(kāi)發(fā)調(diào)試。
1.2 驗(yàn)證環(huán)境
創(chuàng)建測(cè)試文件hello_flet.py,輸入以下代碼:
import flet as ft
def main(page: ft.Page):
page.title = "驗(yàn)證環(huán)境"
page.add(ft.Text("Flet環(huán)境配置成功!"))
ft.app(target=main)
運(yùn)行后若彈出窗口顯示文字,說(shuō)明環(huán)境配置正確。這個(gè)簡(jiǎn)單示例展示了Flet的核心開(kāi)發(fā)模式:通過(guò)ft.app()啟動(dòng)應(yīng)用,在main()函數(shù)中定義頁(yè)面布局和交互邏輯。
二、核心組件開(kāi)發(fā):構(gòu)建編輯器骨架
2.1 創(chuàng)建多行文本輸入框
文本編輯器的核心是TextField組件。以下代碼創(chuàng)建了一個(gè)支持自動(dòng)換行、滾動(dòng)和自定義光標(biāo)的輸入?yún)^(qū)域:
text_field = ft.TextField(
multiline=True, # 啟用多行輸入
expands=True, # 填充可用空間
wrap=True, # 自動(dòng)換行
scrollable=True, # 啟用滾動(dòng)條
cursor_color="blue", # 光標(biāo)顏色
min_lines=20, # 最小顯示行數(shù)
content_padding=ft.padding.all(10) # 內(nèi)邊距
)
這些參數(shù)組合實(shí)現(xiàn)了類似專業(yè)編輯器的輸入體驗(yàn)。特別要注意expands=True和min_lines的配合使用,前者確保組件隨窗口縮放,后者設(shè)定最小高度防止內(nèi)容過(guò)少時(shí)界面塌陷。
2.2 實(shí)現(xiàn)數(shù)據(jù)持久化
傳統(tǒng)編輯器需要手動(dòng)點(diǎn)擊保存,我們通過(guò)實(shí)時(shí)監(jiān)聽(tīng)實(shí)現(xiàn)自動(dòng)保存功能。核心邏輯封裝在TextEditor類中:
import os
FILE_PATH = "editor_content.txt"
class TextEditor(ft.UserControl):
def __init__(self):
super().__init__()
self.text_field = None
def save_text(self, text):
with open(FILE_PATH, "w", encoding="utf-8") as f:
f.write(text)
def load_text(self):
if os.path.exists(FILE_PATH):
with open(FILE_PATH, "r", encoding="utf-8") as f:
return f.read()
return "歡迎使用智能編輯器\n內(nèi)容自動(dòng)保存..."
def on_text_change(self, e):
self.save_text(self.text_field.value)
def build(self):
initial_text = self.load_text()
self.text_field = ft.TextField(
# ...(同上參數(shù)配置)
value=initial_text,
on_change=self.on_text_change
)
return self.text_field
這個(gè)實(shí)現(xiàn)包含三個(gè)關(guān)鍵設(shè)計(jì):
- 自動(dòng)加載:實(shí)例化時(shí)讀取文件內(nèi)容
- 實(shí)時(shí)保存:通過(guò)on_change事件觸發(fā)保存邏輯
- 異常處理:文件不存在時(shí)顯示歡迎提示
三、界面美化:打造專業(yè)級(jí)外觀
3.1 主題色定制
Flet支持Material Design 3色彩系統(tǒng),通過(guò)page.update()方法動(dòng)態(tài)切換主題:
def dark_mode(e):
page.theme_mode = ft.ThemeMode.DARK
page.update()
def light_mode(e):
page.theme_mode = ft.ThemeMode.LIGHT
page.update()
# 在頁(yè)面工具欄添加切換按鈕
page.add(
ft.Row(
[
ft.IconButton(ft.icons.LIGHT_MODE, on_click=light_mode),
ft.IconButton(ft.icons.DARK_MODE, on_click=dark_mode)
],
alignment=ft.MainAxisAlignment.END
)
)
3.2 響應(yīng)式布局
采用Row+Column組合實(shí)現(xiàn)自適應(yīng)布局,確保在不同屏幕尺寸下都能完美顯示:
def main(page: ft.Page):
page.title = "智能編輯器"
page.vertical_alignment = ft.MainAxisAlignment.START
page.padding = 20
# 創(chuàng)建工具欄
toolbar = ft.Row(
controls=[
ft.IconButton(ft.icons.SAVE, on_click=save_action),
ft.IconButton(ft.icons.FILE_OPEN, on_click=open_action)
],
alignment=ft.MainAxisAlignment.SPACE_BETWEEN
)
# 主編輯區(qū)
editor = TextEditor()
# 狀態(tài)欄
status_bar = ft.Text("就緒", size=12, color=ft.colors.GREY)
# 組合所有組件
page.add(
toolbar,
ft.Divider(height=1, color=ft.colors.WITH_50),
editor,
ft.Divider(height=1, color=ft.colors.WITH_50),
status_bar
)
關(guān)鍵設(shè)計(jì)點(diǎn):
- 使用Divider組件實(shí)現(xiàn)視覺(jué)分隔
- 通過(guò)padding和spacing參數(shù)控制間距
- 狀態(tài)欄顯示當(dāng)前操作狀態(tài)
四、功能擴(kuò)展:添加專業(yè)級(jí)特性
4.1 文件操作對(duì)話框
集成系統(tǒng)原生文件選擇器,提升用戶體驗(yàn):
async def open_action(e):
file_path = await ft.file_picker.open_file(
title="打開(kāi)文件",
file_type=ft.FileFilter(["txt", "md", "py"])
)
if file_path:
with open(file_path, "r", encoding="utf-8") as f:
editor.text_field.value = f.read()
status_bar.value = f"已打開(kāi): {os.path.basename(file_path)}"
page.update()
async def save_action(e):
file_path = await ft.file_picker.save_file(
title="保存文件",
file_type=ft.FileFilter(["txt"])
)
if file_path:
with open(file_path, "w", encoding="utf-8") as f:
f.write.text_field.value)
status_bar.value = f"已保存: {os.path.basename(file_path)}"
page.update()
4.2 快捷鍵支持
通過(guò)監(jiān)聽(tīng)鍵盤事件實(shí)現(xiàn)常用快捷鍵:
def main(page: ft.Page):
# ...(前文代碼)
def key_handler(e):
if e.key == "s" and e.ctrl:
save_action(None)
elif e.key == "o" and e.ctrl:
open_action(None)
page.on_keyboard_event = key_handler
4.3 語(yǔ)法高亮(進(jìn)階)
借助highlight.js實(shí)現(xiàn)基礎(chǔ)語(yǔ)法高亮,需先創(chuàng)建Web視圖組件:
def create_web_editor():
html_content = """
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" rel="external nofollow" >
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
</head>
<body>
<pre><code class="language-python">{}</code></pre>
</body>
</html>
""".format(editor.text_field.value.replace("\n", "\n"))
return ft.WebView(
content=ft.WebContent(html=html_content),
width=page.width - 40,
height=page.height - 200
)
五、打包部署:一鍵生成多平臺(tái)應(yīng)用
5.1 桌面應(yīng)用打包
使用Flet內(nèi)置命令生成可執(zhí)行文件:
# Windows平臺(tái) flet pack main.py --platform windows --name TextEditor --icon editor.ico # macOS平臺(tái) flet pack main.py --platform macos --name TextEditor
5.2 Web應(yīng)用部署
通過(guò)flet build web命令生成靜態(tài)文件,上傳至任何Web服務(wù)器即可運(yùn)行:
flet build web # 生成的文件位于dist目錄
5.3 移動(dòng)端適配
對(duì)于Android開(kāi)發(fā),需先安裝Flutter SDK并配置Android Studio:
flutter doctor flet pack main.py --platform android
六、性能優(yōu)化與調(diào)試技巧
6.1 減少不必要的更新
使用page.update()時(shí)指定需要更新的組件:
# 低效方式(更新整個(gè)頁(yè)面) page.update() # 高效方式(僅更新?tīng)顟B(tài)欄) status_bar.update()
6.2 異步文件操作
對(duì)于大文件讀寫,使用asyncio避免界面卡頓:
import asyncio
async def async_save(file_path, content):
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, lambda:
with open(file_path, "w", encoding="utf-8") as f:
f.write(content)
)
6.3 內(nèi)存管理
對(duì)于長(zhǎng)時(shí)間運(yùn)行的應(yīng)用,定期清理未使用的資源:
def cleanup():
import gc
gc.collect()
# 釋放WebView等重型組件資源
if hasattr(page, "web_view"):
page.web_view = None
page.update()
七、完整代碼示例
import flet as ft
import os
from pathlib import Path
FILE_PATH = str(Path.home() / "Documents" / "flet_editor_content.txt")
class TextEditor(ft.UserControl):
def __init__(self):
super().__init__()
self.text_field = None
def save_text(self, text):
try:
with open(FILE_PATH, "w", encoding="utf-8") as f:
f.write(text)
except Exception as e:
print(f"保存失敗: {e}")
def load_text(self):
try:
if os.path.exists(FILE_PATH):
with open(FILE_PATH, "r", encoding="utf-8") as f:
return f.read()
return "歡迎使用Flet智能編輯器\n內(nèi)容自動(dòng)保存至文檔文件夾..."
except Exception as e:
return f"加載失敗: {e}"
def on_text_change(self, e):
self.save_text(self.text_field.value)
def build(self):
initial_text = self.load_text()
self.text_field = ft.TextField(
multiline=True,
expands=True,
wrap=True,
scrollable=True,
cursor_color="blue",
min_lines=20,
content_padding=ft.padding.all(10),
value=initial_text,
on_change=self.on_text_change
)
return self.text_field
async def open_action(e):
file_path = await ft.file_picker.open_file(
title="打開(kāi)文件",
file_type=[ft.FileFilter(["txt", "md", "py"])]
)
if file_path:
try:
with open(file_path, "r", encoding="utf-8") as f:
editor.text_field.value = f.read()
status_bar.value = f"已打開(kāi): {os.path.basename(file_path)}"
page.update()
except Exception as e:
status_bar.value = f"打開(kāi)失敗: {e}"
page.update()
async def save_action(e):
file_path = await ft.file_picker.save_file(
title="保存文件",
file_type=[ft.FileFilter(["txt"])]
)
if file_path:
try:
with open(file_path, "w", encoding="utf-8") as f:
f.write(editor.text_field.value)
status_bar.value = f"已保存: {os.path.basename(file_path)}"
page.update()
except Exception as e:
status_bar.value = f"保存失敗: {e}"
page.update()
def key_handler(e):
if e.key == "s" and e.ctrl:
save_action(None)
elif e.key == "o" and e.ctrl:
open_action(None)
def main(page: ft.Page):
global editor, status_bar
page.title = "Flet智能編輯器"
page.vertical_alignment = ft.MainAxisAlignment.START
page.padding = 20
page.theme_mode = ft.ThemeMode.LIGHT
page.on_keyboard_event = key_handler
# 工具欄
toolbar = ft.Row(
controls=[
ft.IconButton(ft.icons.SAVE, on_click=save_action),
ft.IconButton(ft.icons.FILE_OPEN, on_click=open_action),
ft.IconButton(ft.icons.LIGHT_MODE, on_click=lambda e: setattr(page, "theme_mode", ft.ThemeMode.LIGHT) or page.update()),
ft.IconButton(ft.icons.DARK_MODE, on_click=lambda e: setattr(page, "theme_mode", ft.ThemeMode.DARK) or page.update())
],
alignment=ft.MainAxisAlignment.SPACE_BETWEEN
)
# 編輯器
editor = TextEditor()
# 狀態(tài)欄
status_bar = ft.Text("就緒", size=12, color=ft.colors.GREY)
# 組合布局
page.add(
toolbar,
ft.Divider(height=1, color=ft.colors.WITH_50),
editor,
ft.Divider(height=1, color=ft.colors.WITH_50),
status_bar
)
editor = None
status_bar = None
page = None
ft.app(target=main, assets_dir="assets")
八、總結(jié)與展望
這個(gè)200行代碼的編輯器項(xiàng)目展示了Flet的強(qiáng)大能力:
- 開(kāi)發(fā)效率:相比Tkinter/PyQt,代碼量減少60%
- 跨平臺(tái):一次編寫,桌面/Web/移動(dòng)端通用
- 現(xiàn)代化UI:內(nèi)置Material Design 3組件
未來(lái)可擴(kuò)展方向:
- 添加Markdown實(shí)時(shí)預(yù)覽
- 實(shí)現(xiàn)協(xié)作編輯功能
- 集成AI代碼補(bǔ)全
- 開(kāi)發(fā)插件系統(tǒng)
Flet正在顛覆Python GUI開(kāi)發(fā)范式,它讓開(kāi)發(fā)者能像開(kāi)發(fā)Web應(yīng)用一樣輕松創(chuàng)建跨平臺(tái)桌面程序。隨著Flutter 3.0的發(fā)布,F(xiàn)let的性能和功能將持續(xù)進(jìn)化,值得每個(gè)Python開(kāi)發(fā)者關(guān)注。
?到此這篇關(guān)于Python使用Flet打造跨平臺(tái)文本編輯器的文章就介紹到這了,更多相關(guān)Python文本編輯器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python數(shù)據(jù)結(jié)構(gòu):數(shù)據(jù)類型
這篇文章主要介紹了python數(shù)據(jù)結(jié)構(gòu)中的數(shù)據(jù)類型,在?Python?以及其他所有面向?qū)ο缶幊陶Z(yǔ)言中,類都是對(duì)數(shù)據(jù)的構(gòu)成(狀態(tài))以及數(shù)據(jù)?能做什么(行為)的描述,下面我們就來(lái)你看看python數(shù)據(jù)結(jié)構(gòu)中的數(shù)據(jù)類型商務(wù)詳細(xì)介紹,需要的小伙伴可以參考一下2021-12-12
Python利用shutil模塊實(shí)現(xiàn)文件的裁剪與壓縮
shutil可以簡(jiǎn)單地理解為sh+util ,shell工具的意思。shutil模塊是對(duì)os模塊的補(bǔ)充,主要針對(duì)文件的拷貝、刪除、移動(dòng)、壓縮和解壓操作。本文將利用這一模塊實(shí)現(xiàn)文件的裁剪、壓縮與解壓縮,需要的可以參考一下2022-05-05
關(guān)于Python中*args和**kwargs的深入理解
這篇文章主要給大家介紹了關(guān)于Python中*args和**kwargs的相關(guān)資料,*args和**kwargs代表的是變量, 變量前面的 *(星號(hào))才是必須的,也可以寫成*v和**vs;寫成*args和**kwargs只是一個(gè)常用的書寫方式,需要的朋友可以參考下2021-08-08

