概要
fletのFilePickerで毎回つまづくので記事作成しました。
よく読めばドキュメントに書いてあるような気もするのですが、読解力なさすぎでよくわかりませんでした。
というわけで、結論だけさっさとまとめて、後は実例を示してゆきます。
ファイルパスとファイル名はどこに格納されているのか?
ドキュメントを参考にprint文で値を出力していきます(原始的)
example01.pyと同一のディレクトリに「aaa.txt」「bbb.txt」があり、この2つのファイルを開いてテストします。
結局のところprint文の部分が結論です。配列になっていた、というオチでした。
e.filesの中に配列として各ファイルの情報が格納されており、最初(1番目)のファイル名はe.files[0].nameで、パスはe.files[0].pathのように値を取得します。
最初(2番目)のファイル名はe.files[1].nameで、パスはe.files[1].pathのように値を取得します。
allow_multiple=True でも allow_multiple=False でも配列に格納されるようなので、単一のファイルを開くときもe.files[0].nameのようにアクセスします(ここでつまづきました)。
要はeに返してくるので、e[0].xxxx のように値を取得してあげればいいわけです。
↑こちらの方が参考になるかもしれません。
実装例1 ファイルを開くだけのパターン
import flet as ft
def main(page: ft.Page):
def pick_files_result(e: ft.FilePickerResultEvent):
selected_files.value = (
", ".join(map(lambda f: f.name, e.files)) if e.files else "キャンセルしました!"
)
print("selected_filesの中身:",selected_files)
print("e.files[0].nameの中身:",e.files[0].name)
print("e.files[0].pathの中身:",e.files[0].path)
print("e.files[1].nameの中身:",e.files[1].name)
print("e.files[1].pathの中身:",e.files[1].path)
selected_files.update()
pick_files_dialog = ft.FilePicker(on_result=pick_files_result)
selected_files = ft.Text()
page.overlay.append(pick_files_dialog)
page.add(
ft.Row(
[
ft.ElevatedButton(
"ファイルを開く",
icon=ft.icons.UPLOAD_FILE,
on_click=lambda _: pick_files_dialog.pick_files(
allow_multiple=True
),
),
selected_files,
]
)
)
ft.app(target=main)
selected_filesの中身: text {'value': 'aaa.text, bbb.text'}
e.files[0].nameの中身: aaa.text
e.files[0].nameの中身: C:\Users\user\Desktop\flet_example01\aaa.text
e.files[1].nameの中身: bbb.text
e.files[1].nameの中身: C:\Users\user\Desktop\flet_example01\bbb.text
実装例2 ディレクトリを指定するパターン
ディレクトリを指定するFilePicker(on_result=get_directory_result)を使用した場合は、配列ではなく、「e.path」で値を取得できるようです。
import flet as ft
def main(page: ft.Page):
t = ft.Text(value="Program", color="blue")
def pick_files_result(e: ft.FilePickerResultEvent):
selected_files.value = (
", ".join(map(lambda f: f.name, e.files)) if e.files else "キャンセルされました。"
)
selected_files.update()
pick_files_dialog = ft.FilePicker(on_result=pick_files_result)
selected_files = ft.Text()
def get_directry_result(e: ft.FilePickerResultEvent):
selected_directry.value = e.path if e.path else "キャンセルされました。"
print(e.path)
selected_directry.update()
get_directry_dialog = ft.FilePicker(on_result=get_directry_result)
selected_directry = ft.Text()
page.overlay.extend([pick_files_dialog,get_directry_dialog])
page.add(
ft.Row(
[t]
),
ft.Row(
[
ft.ElevatedButton(
"ファイルを開く",
icon=ft.icons.UPLOAD_FILE,
on_click=lambda _: pick_files_dialog.pick_files(
allow_multiple=True
),
),
selected_files,
]
),
ft.Row(
[
ft.ElevatedButton(
"保存フォルダを指定",
icon=ft.icons.UPLOAD_FILE,
on_click=lambda _: get_directry_dialog.get_directory_path(
),
disabled=page.web
),
selected_directry,
]
)
)
ft.app(target=main)
おまけ
途中までですが、「複数のファイルに対して何らかの処理を連続的に行うアプリ」の画面だけ作成してみました。
このあたりからコードは長くなりますね。
公式のコードをそのまま動かして必要な部分を変更するほうが効率よいかもしれません。
import flet as ft
def main(page: ft.Page):
# Topの文字表示
t = ft.Text(value="Program", color="blue")
# ダイアログの表示yes → 処理
def handle_close_yes(e):
page.close(dlg_modal)
#ここに実行時の処理
print("hello")
page.add(ft.Text(f"Modal dialog closed with action: {e.control.text}"))
# ダイアログの表示no
def handle_close_no(e):
page.close(dlg_modal)
page.add(ft.Text(f"Modal dialog closed with action: {e.control.text}"))
dlg_modal = ft.AlertDialog(
modal=True,
title=ft.Text("Please confirm"),
content=ft.Text("Do you really want to delete all those files?"),
actions=[
ft.TextButton("Yes", on_click=handle_close_yes),
ft.TextButton("No", on_click=handle_close_no),
],
actions_alignment=ft.MainAxisAlignment.END,
on_dismiss=lambda e: page.add(
ft.Text("Modal dialog dismissed"),
),
)
# ファイルを開く
def pick_files_result(e: ft.FilePickerResultEvent):
selected_files.value = (
", ".join(map(lambda f: f.name, e.files)) if e.files else "キャンセルされました。"
)
selected_files.update()
pick_files_dialog = ft.FilePicker(on_result=pick_files_result)
selected_files = ft.Text()
# ディレクトリを開く(保存先の指定)
def get_directry_result(e: ft.FilePickerResultEvent):
selected_directry.value = e.path if e.path else "キャンセルされました。"
print(e.path)
selected_directry.update()
get_directry_dialog = ft.FilePicker(on_result=get_directry_result)
selected_directry = ft.Text()
# ドロップダウン
def dropdown_changed(e):
page.update()
t_drop_pre = ft.Text()
t_drop_pre.value = "保存方法:"
t_drop_post = ft.Text()
dropdown = ft.Dropdown(on_change=dropdown_changed,label="いずれかを選んでください",
width=450,
options=[
ft.dropdown.Option("もとファイル名の終わりに文字列を追加"),
ft.dropdown.Option("新規フォルダを作成してその中に保存する"),
],
)
fnaddstr_field = ft.TextField(label="追加する文字列",width=200,autocorrect=False)
newdirname_fielf = ft.TextField(label="新規フォルダ名",width=200,autocorrect=False)
page.overlay.extend([pick_files_dialog,get_directry_dialog])
page.add(
ft.Row(
[t]
),
ft.Row(
[
ft.ElevatedButton(
"ファイルを開く",
icon=ft.icons.FILE_OPEN,
on_click=lambda _: pick_files_dialog.pick_files(
allow_multiple=True
),
),
selected_files,
]
),
ft.Row(
[t_drop_pre,dropdown,t_drop_post,fnaddstr_field,newdirname_fielf
]
),
ft.Row(
[
ft.ElevatedButton(
"保存フォルダを指定",
icon=ft.icons.FOLDER_OPEN,
on_click=lambda _: get_directry_dialog.get_directory_path(
),
disabled=page.web
),
selected_directry,
]
),
ft.Row(
[
ft.ElevatedButton("実行する",width=180,on_click=lambda e: page.open(dlg_modal)),
]
)
)
ft.app(target=main)
おわりに
取得するのはファイル名とパスだけなので、実際にファイルに対して何らかの処理をするときにはこのファイルパスを指定することになります。
また、ファイルを開いたときに処理を行うのか、あるいはその他のボタンを押して処理を行うのかによって、処理内容を書く場所が変わってきます。
その他のボタンで処理する場合は、ファイルが選択済みかどうかをif文で判断する必要があります。