1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Flet】2つのドロップダウンを連動させる

Last updated at Posted at 2023-05-19

Fletで2つのドロップダウンを連携させる方法について書きます。
1つ目のドロップダウンで選択したものに応じて2つ目のドロップダウンの選択肢が変化します。

動作イメージはこんな感じです。
Videotogif (1).gif

Fleについてはこちらの記事がわかりやすいです。

ドロップダウンの公式リファレンスはこちら

この記事は自分の備忘録に近いのでご容赦ください。

コード

やや長いので分割して説明を書いていきます。
最後にコード全体を示します。

ざっくり処理の流れを書くと、
1.親ドロップダウンが選択される

2.表示内容をすべて削除

3.子ドロップダウンの選択肢を生成

4.表示内容を生成

5.ページの表示を更新する

1に戻る
この繰り返しになります。

どうやらドロップダウンの選択肢はそのドロップダウンが生成されたときの内容で固定されるので、選択肢を更新するために表示内容ごと一度削除しています。
理想的なのは子ドロップダウンのみ削除、再生成することですが特定のコントロールのみを指定して削除することができなかったのでこの形になりました。

ドロップダウンの作成

最初に表示するドロップダウンの作成を行います

この時、一緒にドロップダウンの選択肢である辞書を作成します。
今回は辞書を使いましたがlistpandas.DataFrameでも同様のことができると思います。

ここからは、便宜上最初に選択するドロップダウンを親、2つ目に選択するドロップダウンを子として表記します。

import flet as ft #fletをインポート

class Display(ft.UserControl): #コンポーネントの作成
    def __init__(self, page:ft.Page):
        super().__init__() #コンポーネント化に必要
        self.page = page #page情報の読み込み

    
    def build(self):
        # 選択肢の辞書を作成
        self.options_dict = { 
            "大文字":["A","B","C"],
            '小文字': ["a","b","c"],
            '数字': [1,2,3]
        }

        # 親のドロップダウンの作成
        self.select_key = ft.Dropdown(
            value =None, #初期値
            on_change=self.on_change_key, #選択肢が選択されたときの動作
            options=self.select_key_options() #親の選択肢
        )
        
        #子のドロップダウンの作成
        self.select_item = ft.Dropdown(
            value = None, #初期値
            options= self.select_item_options(self.select_key.value) #子の選択肢
        )

        #表示内容
        self.view=ft.Column(
            controls=[
                self.select_key,
                self.select_item
            ]
        )

        return self.view

ドロップダウンについて
・初期値は選択肢にあるものならNone以外でもOK
・親のon_changeは必ず必要。子の選択肢の生成と表示の更新を行うon_change_keyを指定している
・親のoptionsは公式リファレンスのようにべた書きでもOKだが、今回は辞書から選択肢を生成するため関数を指定している
・詳しくは後述するが、ページの削除と生成が繰り返されるのでoptionsには必ず選択肢を生成する関数の返り値を指定する

表示内容について
・ページの削除と生成を繰り返すために一度変数viewにいれてから、その変数を返すという書き方にしています

ドロップダウンが変更されたときの処理

先ほどのドロップダウンのon_changeoptionsに指定した関数が後に続きます。
これらの関数はclassの中に入っています。

    def on_change_key(self,e): #親の選択肢が変更されたときの関数
        self.page.controls.pop() #ページの内容をすべて削除
        self.select_item.options =self.select_item_options(self.select_key.value) #子の選択肢を生成されたものに変更
        self.page.controls.append(self.view) #ページの内容を再生成
        self.page.update() #ページの表示を更新

    def select_key_options(self): #親の選択肢を生成する関数
        key_list = list(self.options_dict.keys()) #辞書からキーのみを取り出す
        key_option_list = [] #選択肢を入れるリストを用意
        for i in key_list:
            key_option_list.append(ft.dropdown.Option(text=i)) #選択肢を生成
        return key_option_list #選択肢のリストを返す

    def select_item_options(self,key_value): #子の選択肢を生成する関数、引数は親で選択された値
        item_option_list = [] #選択肢を入れるリストを生成
        if key_value != None: #親が選択されている時
            item_list = self.options_dict[key_value] #辞書から選択肢の名前を取得
            for i in item_list:
                item_option_list.append(ft.dropdown.Option(text=i)) #選択肢を生成
        return item_option_list

前述したようにドロップリストの選択肢は生成時に固定されるようなので、子の選択肢を更新した後は必ずページの削除と再生成が必要です。上に提示したコードでは削除→更新→再生成の順番ですが、更新→削除→再生成でも問題なくできました。

コードの全体

このコードをコピペすれば最初に示したGIFのように動作するはずです。

import flet as ft

class Display(ft.UserControl):
    def __init__(self, page:ft.Page):
        super().__init__()
        self.page = page

    
    def build(self):
        self.options_dict = {
            "大文字":["A","B","C"],
            '小文字': ["a","b","c"],
            '数字': [1,2,3]
        }

        self.select_key = ft.Dropdown(
            value ="大文字",
            on_change=self.on_change_key,
            options=self.select_key_options()
        )

        self.select_item = ft.Dropdown(
            value = None,
            options= self.select_item_options(self.select_key.value)
        )


        self.view=ft.Column(
            controls=[
                self.select_key,
                self.select_item
            ]
        )

        return self.view

    def on_change_key(self,e):
        self.select_item.options =self.select_item_options(self.select_key.value)
        self.page.controls.pop()
        self.page.controls.append(self.view)
        self.page.update()

    def select_key_options(self):
        key_list = list(self.options_dict.keys())
        key_option_list = []
        for i in key_list:
            key_option_list.append(ft.dropdown.Option(text=i))
        return key_option_list

    def select_item_options(self,key_value):
        key_value = self.select_key.value
        item_option_list = []
        if key_value != None:
            item_list = self.options_dict[key_value]
            for i in item_list:
                item_option_list.append(ft.dropdown.Option(text=i))
        return item_option_list
        

def main(page:ft.Page):
    page.add(Display(page))

ft.app(target=main)

また何かわかったことがあれば追記したいと思います。(特に表示内容の削除周り)

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?