蛇使いな彼女BLOG
【第108回】Fletを使ったアプリケーション開発
2024.07.05

こんにちはモトハシです。
今日はFletという比較的新しいアプリケーション開発用のフレームワークを使って前回紹介したプログラムの一部をWEB上で動かせるか試してみようと思います。
Fletに目を付けた理由は、TkinterやPysimpleGUIと比べて視覚的にも見やすく、WEBアプリやモバイルアプリにも対応している柔軟性からです。
また、以前記事で紹介したことのあるPysimpleGUIは今年2月にリリースされたバージョン5から商用利用が有償化されたらしく、ライセンスの取得が必要になったようです。
こういった背景からモトハシの立場でも利用しやすいFletを使っていこうと思います。
Fletを使用する際は、前提としてFlutter SDK 3.16 以降のインストールが必須です。(Windowsの場合は公式ページからパッケージをインストールします)
あと、VisualStudioを使ってない方はこれもインストールが必要になる様子。
以下はコマンドでインストール結果を確認したときのスクショです。


赤い×印の部分など、いくつか拡張機能のインストールも要求されるので、本当なら詳しく説明したいところですが、現在ネット事情でひと月の20日以上、日中深夜明け方関係なくほぼ連続でサーバー接続に失敗するのでこれらのスクリーンショットを撮るのがやっとでした😭
詳しい事はすみませんが各自調べてみてください。
開発環境が整ったら環境変数にパスが通っているか確認して、なければ追加します。

モトハシはflutterと、一番下の変数Pathの2カ所に追加しておきました。
FletはWindowsのアプリ開発にVisual Studio Community 2022を推奨していますが、2022をインストールさえしておけば、他のバージョンでコーディングしても問題ないようなので私は2019で以下のようなアプリケーションを作成しました。
テキストフィールドに観測地点を入力し、検索ボタンを押すと、予めデータベースに登録されている情報から該当する地点を検索してそのコード情報を表示します。

ページ構成はいたってシンプルですが、ボタンイベントによるデータベースとのセッション結果を構造の最上位部分である“ft.Page”に反映する方法に関してはかなり試行錯誤しました。
アプリケーション本体であるmainファンクションで全てのウィジェットを追加してしまうと、イベントによる表示の変更が出来なかった為、いろいろと検討した結果最終的に可変コンテンツであるDataTableはデータベースの検索情報を元に組み立てた後、各ウィジェットの上位であるColumn.controls、Row.controlsを駆使して追加しました。

ではコード全体を示します。
import numpy as np
import flet as ft
import sqlite3
import os
path=os.path.join(os.path.abspath('__file__'),'../obs_stations.sqlite')
# ==IconButton event action==
class Input_station:
def __init__(self,station='',sql=path,):
self.station=station
self.sql=sql
self.conn = sqlite3.connect(self.sql)
self.cur = self.conn.cursor()
self.cur.execute('SELECT * FROM location WHERE station_name =?',( self.station ,))
self.data=self.cur.fetchall()
self.conn.close()
if len(self.data)==1:
self.data=self.data[0]
else:
self.data=('','','')
# ==pubsub additional content==
class Create_Table(ft.Row):
def __init__(self, station):
super().__init__()
# Required : controls=[]
self.controls=[ft.DataTable(
columns=[
ft.DataColumn(ft.Text('station_id',size=18,color=ft.colors.GREY)),
ft.DataColumn(ft.Text('station_name',size=18,color=ft.colors.GREY)),
ft.DataColumn(ft.Text('fuken_id',size=18,color=ft.colors.GREY))
],
rows=[
ft.DataRow(
cells=[
ft.DataCell(ft.Text(station[0],size=16,color=ft.colors.GREY)),
ft.DataCell(ft.Text(station[1],size=16,color=ft.colors.GREY)),
ft.DataCell(ft.Text(station[2],size=16,color=ft.colors.GREY)),
],
on_select_changed=print('Running')
)
]
)
]
def main(page: ft.Page):
# setting
page.title = "Flet MyApp"
page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
page.bgcolor = ft.colors.WHITE
page.window_left = 400
page.window_top = 400
# appbar
page.appbar = ft.AppBar(
leading=ft.Icon(ft.icons.FOUNDATION),
leading_width=40,
title=ft.Text("My app"),
center_title=False,)
# function
def event(e):
page.pubsub.send_all(Input_station(station=input_location.value))
'''
new_table=Create_Table(Input_station(station=input_location.value).data)
Table.controls.append(new_table)
'''
page.update()
def on_click_button(station_info:Input_station):
new_table=Create_Table(station_info.data)
if Table.controls != []:
Table.controls.pop()
Table.controls.append(new_table)
page.update()
# content
input_location=ft.TextField(border=ft.InputBorder.NONE,filled=True,hint_text="location search")
event_button=ft.IconButton(icon=ft.icons.SEARCH,icon_color='black', on_click=event)
Table = ft.Column(width=400,)
# Pass event input to the page
page.pubsub.subscribe(on_click_button)
View=ft.Column(
width=400,
controls=[
ft.Row(
controls=[
input_location,
event_button,
],
),
]
)
page.add(View,Table)
page.update()
ft.app(main,view=ft.AppView.WEB_BROWSER, web_renderer=ft.WebRenderer.HTML)
※上記のMain.pyは、プロンプトから“flet create (my app name)”のコマンドで作成したものです。VisualStudioのソリューションファイルではないので、詳しくは公式ガイドを確認してください。
オブジェクトが2つとアプリ本体(main)で、コードが大きく3つの塊に分かれています。
クラスInput_stationはIconButtonが押されたときのイベントとして機能し、mainファンクション内のpage.pubsub.send_all()によってアプリケーションのページへ転送されます。
def event(e):
page.pubsub.send_all(Input_station(station=input_location.value))
'''
new_table=Create_Table(Input_station(station=input_location.value).data)
Table.controls.append(new_table)
'''
page.update()
このとき転送される情報は、TextFieldに入力した地点のコード情報です。地点がデータベース上で見つからなかった場合は“”が返されます。
(eventファンクション内でコメントアウトしているコードがありますが、page.pubsub.send_allの代わりにこの2行を追加することで、サブスクライブ(登録)処理を行わず、イベント処理だけでデータの転送とDataTableの表示を行う事も出来ます。)
# content
input_location=ft.TextField(border=ft.InputBorder.NONE,filled=True,hint_text="location search")
event_button=ft.IconButton(icon=ft.icons.SEARCH,icon_color='black', on_click=event)
Table = ft.Column(width=400,)
# Pass event input to the page
page.pubsub.subscribe(on_click_button)
pubsubのパブリッシュサブスクライブ機能を使うためには、表示しているページのどこに情報を送るのか予め明示しておかなければいけません。
上記の場合、page.pubsub.subscribe(on_click_button)でページに登録を行います。
転送されたデータはおそらくon_click_buttonの任意引数の値として取得されています。
詳しく確認していませんが多分こういうこと→on_click_button(引数=Input_station)
今回値がテキストや数値、リストなどではなくクラスオブジェクトなので、オブジェクトの中身を参照するためにon_click_button(station_info:Input_station)と明記していますが、本来はボタンイベントと同様に適当な引数を入力すればいいようです。
システムが複雑で説明が難しいのですが、とにかく
page.pubsub.send_all(渡したい値)⇒pubsub.subscribe(function(*)) で、渡したい値は*に送られます。
長くなりましたが今回はここまで!
次回はビルドをしていきます。

06-6657-5130
sales@hydrolab.co.jp