fletのFilePickerの基本を理解する(GUIアプリ作成入門)

# １．概要

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809517/04666db0-d784-9705-6958-2f418fa69d09.png)


fletのFile Pickerの機能がわかりにくかったのでここにまとめておきます。

以下を参考にしています。

https://flet.dev/docs/controls/filepicker/

https://flet.dev/docs/reference/types/filepickerfile/



# １．ファイルパスとファイル名はどこに格納されているのか？

ドキュメントを参考にprint文で値を出力してみました。

https://github.com/flet-dev/examples/blob/main/python/controls/file-picker/file-picker-all-modes.py

↑ここを参考にしています。

# (1) ファイルを開くだけのパターン

```diff_python:example01.py
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)
```

example01.pyと同一のディレクトリに「aaa.txt」「bbb.txt」があり、この2つのファイルを開いてテストします。

```:出力結果
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
```


e.filesに配列として格納されている情報を取得することで、ファイル名、パスを取得できます。

<b>最初(1番目)配列はファイル名で「e.files[0].name」、パスは「e.files[1].path」のように取得します。

allow_multiple=True でも　allow_multiple=False でも配列に格納されるようなので、<b>単一のファイルを開くときもe.files[0].nameのようにアクセスします（ここでつまづきました）。</b>

要はeに返してくるので、e[0].xxxx のように値を取得してあげればいいわけです。


## (2) ディレクトリを指定するパターン

ディレクトリを指定するFilePicker(on_result=get_directory_result)を使用した場合は、<b>配列ではなく、「e.path」</b>で値を取得できるようです。

```python:example02.py
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)
```

# ２．おまけ　

途中までですが、<b>「複数のファイルに対して何らかの処理を連続的に行うアプリ」</b>の画面だけ作成してみました。

このあたりからコードは長くなりますね。

公式のコードをそのまま動かして必要な部分を変更するほうが効率よいかもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809517/eb20e113-c1aa-4103-a3df-0088db1ee7f4.png)


```python:wxample03.py
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)
```

# まとめ

取得するのはファイル名とパスだけなので、<b>実際にファイルに対して何らかの処理をするときにはこのファイルパスを指定</b>することになります。

また、<b>ファイルを開いたときに処理を行うのか、あるいはその他のボタンを押して処理を行うのか</b>によって、処理内容を書く場所が変わってきます。

その他のボタンで処理する場合は、ファイルが選択済みかどうかをif文で判断する必要があります。