【Flutter】excelマクロで作成したjsonファイルを読み込んでみる
概要
製造部で使用するようなexcelファイルにマクロを埋め込んで、マクロからjsonファイルを作成しFlutterのアプリ実行から設定値を読み込んでみました。
1. excelファイルからjsonファイル作成
1.1. excelファイル
下記のように製造部が入力するタブとマクロを実行するタブを作成しました。
また、データ入力を試すために、bool型・int型・List<int>型・double型・String型・List<String>型でそれぞれ行ってみました。
セルの計算式については、一部コメントで表示しておきます(本当は、githubでファイルをダウンロードできるようにするのがよいのでしょうが…)。コメントの「あり・なし_範囲」はありとなしをtrue/falseに割り付けたテーブルを参照しているところです(選択テーブルは省略)。
1.2. excelファイルのマクロ
作成ボタンを押すと、文字コードUTF-8でBOM消してjsonファイルを作成するようにマクロを作成しました。BOMについては他のHPを参照して下さい。マクロコードについては【EXCEL VBA】BOM無しUTF-8でCSVファイル出力をしたいを参考にさせて頂きました。
Sub ファイル作成_Click()
'警告表示無効:上書き警告を表示しない
Application.DisplayAlerts = False
'ファイル出力:設定表.xlsmと同じパスにファイルを作成
Dim ret As Boolean
ret = WriteUTF8(ThisWorkbook.Path, "test.json")
'メッセージボックス表示時の砂時計表示防止:矢印型ポインタに変更
Application.Cursor = xlNorthwestArrow
If ret = True Then
'メッセージボックス表示
MsgBox ("test.json を作成しました ")
Else
'メッセージボックス表示
MsgBox ("失敗しました ")
End If
'標準ポインタに変更
Application.Cursor = xlDefault
'プロパティ設定表.xlsmファイルを閉じるときの保存確認のメッセージを表示させない
ActiveWorkbook.Saved = True
'警告表示有効
Application.DisplayAlerts = True
End Sub
'UTF8形式でファイル作成
Public Function WriteUTF8(dir As String, filename As String) As Boolean
WriteUTF8 = False
Dim A, B
A = dir & "\" & filename
On Error GoTo err
Dim adb As New ADODB.stream
With adb
.Type = adTypeText
.Charset = "UTF-8"
.Open
End With
'ファイル書込み
With ActiveSheet.UsedRange
For i = 1 To .Rows.Count
adb.WriteText Cells(i, 1), 1
Next
End With
'BOMを削除する
adb.Position = 0
adb.Type = 1
adb.Position = 3
B = adb.Read
adb.Close
adb.Open
adb.Write B
'保存するファイルを指定
adb.SaveToFile A, 2
adb.Close
WriteUTF8 = True
err:
End Function
1.3. jsonファイル作成
作成ボタンを押してjsonファイルを作成します。
BOMが残った場合、適当なバイナリエディタソフトで見てみると下記のような部分があります。これがあるとプログラム上で読み込めないということがあるので注意します。
2.アプリ実装
【Flutter】JSON形式でローカルファイルにデータ保存(json_serializable)で紹介(大変分かりやすくて助かりました。ありがとうございました!!)されているコードとほとんど一緒ですが、excelファイルの各データにあわせるため一部改変しています。
2.1. パッケージインストール
flutter pub add json_annotation path_provider build_runner json_serializable
flutter pub get
2.2. pubspec.yaml編集
build_runnerとjson_serializableをdev_dependenciesの下に記載し直す。
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
json_annotation: ^4.8.1
path_provider: ^2.1.3
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
build_runner: ^2.4.9
json_serializable: ^6.7.1
2.3. json_setting.dart作成
jsonデータを入力するクラスを作成。作成した後にエラーが出ていますが2.4を実行するまで問題はありません。
import 'package:json_annotation/json_annotation.dart';
part 'json_settings.g.dart'; // flutter pub run build_runner build --delete-conflicting-outputs(後述)で生成されるファイル名
@JsonSerializable()
class JsonSettings {
// セーブしたい情報を変数にする
final bool bool_value;
final int int_value;
final List<int> int_list;
final double double_value;
final String string_value;
final List<String> string_list;
JsonSettings(
{required this.bool_value,
required this.int_value,
required this.int_list,
required this.double_value,
required this.string_value,
required this.string_list});
factory JsonSettings.fromJson(Map<String, dynamic> json) =>
_$JsonSettingsFromJson(json);
Map<String, dynamic> toJson() => _$JsonSettingsToJson(this);
}
2.4. ターミナル実行
下記コマンドをターミナルで実行すると、下記クラスが作成されます。
flutter pub run build_runner build --delete-conflicting-outputs
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'json_settings.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
JsonSettings _$JsonSettingsFromJson(Map<String, dynamic> json) => JsonSettings(
bool_value: json['bool_value'] as bool,
int_value: json['int_value'] as int,
int_list:
(json['int_list'] as List<dynamic>).map((e) => e as int).toList(),
double_value: (json['double_value'] as num).toDouble(),
string_value: json['string_value'] as String,
string_list: (json['string_list'] as List<dynamic>)
.map((e) => e as String)
.toList(),
);
Map<String, dynamic> _$JsonSettingsToJson(JsonSettings instance) =>
<String, dynamic>{
'bool_value': instance.bool_value,
'int_value': instance.int_value,
'int_list': instance.int_list,
'double_value': instance.double_value,
'string_value': instance.string_value,
'string_list': instance.string_list,
};
- main.dart
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:json_settings_sample2/json_settings.dart';
import 'package:path_provider/path_provider.dart';
void main() {
final app = MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyApp(),
);
runApp(app);
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String output = '';
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
// セーブボタン
onPressed: () async {
// クラス生成
final sd1 = JsonSettings(
bool_value: true,
int_value: 2,
int_list: [3, 5, 8],
double_value: 2.57,
string_value: "こんにちは",
string_list: ["ab", "149"],
);
// セーブするファイル名を決定
final directory = await getExternalStorageDirectory();
final path = '${directory?.path}/test.json';
final file = File(path);
// print('出力パス = $path');
// String型に変換して保存
final jsonString = json.encode(sd1.toJson());
file.writeAsStringSync(jsonString);
// print('書き込み内容 = $jsonString');
// 表示するテキスト
setState(() {
output =
'セーブ(bool = ${sd1.bool_value}\n, int = ${sd1.int_value}\n, int_list = ${sd1.int_list}\n, double = ${sd1.double_value}\n, String = ${sd1.string_value}\n, String_list = ${sd1.string_list}\n )';
});
},
child: const Text('Save'),
),
// ロード
ElevatedButton(
onPressed: () async {
// 参照するファイルを取得
final directory = await getExternalStorageDirectory();
final path = directory?.path;
final file = File('${path}/test.json');
// データ読み込み
final jsonString = file.readAsStringSync();
print("json=$jsonString");
final sd2 = JsonSettings.fromJson(jsonDecode(jsonString));
// 表示するテキスト
setState(() {
output =
'ロード(bool = ${sd2.bool_value}\n, int = ${sd2.int_value}\n, int_list = ${sd2.int_list}\n, double = ${sd2.double_value}\n, String = ${sd2.string_value}\n, String_list = ${sd2.string_list}\n )';
});
},
child: const Text('load'),
),
// outputを表示
Text(
'output\n$output',
style: const TextStyle(
fontSize: 30,
),
)
],
),
),
);
}
}
- 実行
アプリケーション内フォルダにexcelから作成したjsonファイルを入れ、アプリを実行します。
loadボタンを押すとjsonデータをロードして表示されます。
おわりに
以上、excelマクロで作成したjsonファイルを読み込んでみるという記事でした。最後まで読んで頂きましてありがとうございました。
今回はjson形式でファイルを作成しましたが、正直なところdartで簡単にロードできるのならどのデータ形式でも構わないのですが、今までjsonファイルを設定ファイルとして使用してきたことがなかったので、いい勉強になりました。
また、mainコードでjsonデータをロードをしていますが、設定ファイル内のデータがプログラム内のデータとすべて一致する場合には問題なく動作します。ですが、設定ファイル内のデータが足りない場合はたぶんエラーが起きるんじゃないか(試していません)と思います。実際に使用する場合は、一部データがない場合も想定しデフォルト値を入れるような処理をする部分を作成する必要があるんじゃないかと思います(もしくは、assetsにデフォルトファイルを用意するとか)。
参考
Discussion