実行時型情報を使うとプログラムを書かずにプログラムが完成する

 # はじめに
 みなさんは**実行時型情報**を使ったことはありますか？
 おそらく使ったことがない、知らないと言う人がほとんどだと思われます
 ですが実行時型情報を使うとプログラムを作るときに必ずと言って必要な**ある事**をする必要がなくなります

 # でもそれって面倒ですよね？
 実行時型情報を理解するには非常に時間と手間がかかります
 で・す・の・で

 私がみなさんの代わりに学習したものを公開します！

# どれぐらい便利になるのか実演
疑い深いみなさんのために　もうサンプルも作ってあります

ダウンロードはここから
https://drive.google.com/uc?id=1rwprEX5SR2oP6TH8km7VhmvvZ4R4OL-a

こんなデータクラスがあります

~~~data.pas
type
  TDataConfig = class(TPersistent)
  private
    { Private 宣言 }
    FAviutlStayOnTop   : Boolean;
    FTrayIcon          : Integer;
    FStayOnTop         : Boolean;
    FData1              : Boolean;
    FFilename          : string;
    FNoEdit            : string;
    FNoView            : string;
    FText              : string;
    FColor: TColor;
    FFontName: string;
    FFolder: string;
  public
    { Public 宣言 }

 published
    property AviutlStayOnTop : Boolean read FAviutlStayOnTop write FAviutlStayOnTop;
    property TrayIcon : Integer read FTrayIcon write FTrayIcon;
    property StayOnTop : Boolean read FStayOnTop write FStayOnTop;
    property Data1 : Boolean read FData1 write FData1;
    property NoEdit : string read FNoEdit write FNoEdit;
    property NoView : string read FNoView write FNoView;
    property Text2 : string read FText write FText;
    property FontName : string read FFontName write FFontName;
    property Filename : string read FFilename write FFilename;
    property Folder : string read FFolder write FFolder;
    property Color : TColor read FColor write FColor;
  end;
~~~

様々な型をプロパティとして実装しています
みなさんもこういうのを必ず1つは作りますよよね？

そして次に面倒な事が起こります

**このデータクラスを表示、編集したい**

当たり前のように必要な機能です

みなさんはどうしていますか？
フォームやフレームを作ってエディットクラス、チェックボックス、コンボボックスを組み合わせた画面を設計して
表示するイベントでクラスの内容を1つ1つ関係するクラスに反映させて表示させて
次にそのクラスの変更イベントで値を変えて
あーもう面倒で仕方がありません

ではサンプルを実行してみましょう

# 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637460/f8baf512-45b9-85fa-d3dd-7e72de749481.png)

先ほどのデータクラスのプロパティが表示されています
もちろん編集もできます

え？そういうプログラムを書いているんだから表示編集できて当たり前？
そう思う人はプログラムを覗いてみてください
このプログラムにクラスを1つ1つ表示したりイベントに反応して値を変えているらしきとことが無いように見えます
それ以前にそれっぽい編集フォームやフレームも存在していません

どこかにこっそりと書いているんだ！と思う人はデータクラスに要素を追加してみてください
クラスに要素を追加すると編集画面にも反映されます
信じて頂けましたか？
つまりこのサンプルを使えばもう環境設定画面を作らなくていいのです

# 使い方
TListViewEditRttiクラスが値を表示したり編集したりするクラスです
このクラスを定義します

```teigi.pas
FListRtti2 : TListViewEditRtti;
```
生成します
```create.pas
  FListRtti2 := TListViewEditRtti.Create(Self);
  FListRtti2.Parent := tsListRtti2;
  FListRtti2.Align := alClient;
```

表示します dが表示編集させたいクラス
```show.pas
  FListRtti2.ItemHeight := 32;
  FListRtti2.LoadFromObject(d);
  FListRtti2.Update();
```

以上です

本当はLoadFromObjectとUpdateは1つにしたかったのですが、ちらつき防止とかいろいろ意味があります

# かゆいところに手が届く機能
最初の状態ではプロパティ名が項目の名称になっているので流石にかっこ悪いですよね？でもサンプルの一部は日本語になっています
項目名は変えることが出来ます

```sanple.pas
FListRtti2.Rttis['StayOnTop'].Caption := '常に上';
```
StayOnTopという名称のプロパティの項目名を「常に上」に変更します
これをLoadFromObjectとUpdateの間に挟んで下さい
LoadFromObjectが型解析でUpdateが表示になっています
その中間に様々な処理を挟むことでどんな表示も可能です

StayOnTopはBoolean型なので値はTrueとFalseになっていますが、そんな表示は格好悪いので

```sample.pas
  ts := FListRtti2.Rttis['StayOnTop'].Strings;
  ts.Clear;
  ts.Add('なし');
  ts.Add('あり');
```
これでTrueとFalseの代わりに「あり」と「なし」が表示されます

プロパティ名TrayIconはアイコンの状態を示す数値で0:標準 1:最大 2:最小 というのに数値で選ぶのは大変です
そういう場合コンボボックスを用意してます

```sample.pas
  FListRtti2.AddCaption('TrayIcon','アイコンの種類','リストから選択',ListViewEditTypeComboBox);
    ts := FListRtti2.Rttis['TrayIcon'].Strings;
  ts.Clear;
  ts.Add('標準');
  ts.Add('最大');
  ts.Add('最小');
```
左からプロパティ名、項目の表示、ヒントの内容、型や編集する方法式を示すユニークIDです
これでそれぞれの数値にしたがった表示となって編集はコンボボックスになり設定されるのは0,1,2の数値になります

値が順番だったので対応出来ましたが 1:標準 2:最大 4:最小 という場合は困りますね
そういう場合は

```sample.pas
  FListRtti2.AddCaption('TrayIcon','アイコンの種類','リストから選択',ListViewEditTypeComboBoxObjectId);
    ts := FListRtti2.Rttis['TrayIcon'].Strings;
  ts.Clear;
  ts.AddObject('標準',TObject(1));
  ts.AddObject('最大',TObject(2));
  ts.AddObject('最小',TObject(4));
```
これで  1:標準 2:最大 4:最小 という値にしたがって表示され、コンボボックスで選択すると1,2,4の数値が代入されます

編集されたくない場合は ListViewEditTypeNoEditId を指定し、表示もさせたくない場合は ListViewEditTypeHideId を指定します

ここまでが標準の機能です ここまで使う場合は usesで定義するユニットはTListViewEditRttiが定義されているクラスと合わせて2～3クラスになります

# プラグインの追加
Delphiにプラグインの概念が用意されていないので作りました

まずはダイアログ関係のプラグインです
プラグインを使うには
implementation 以降のusesに ListViewEditDialog を追加します
これで自動的にダイアログ関係のプラグインが実装されます

## ファイル選択プラグイン
```sanmple.pas
  FListRtti2.Rttis['Filename'].EditType := ListViewEditOpenDialogId;
  ListViewEditOpenDialog.OpenDialog.Filter := 'test(*.txt) | *.txt';
```
編集方法に ListViewEditOpenDialogId を指定するとファイル選択プラグインで編集されます
Filenameが編集状態になると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637460/11323c42-80e5-f9c1-5213-d1ed7e6b8332.png)

「...」付きの編集になり「...」をクリックすると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637460/3d0b4cdc-b9b2-8a3e-a2a9-864c92304cf0.png)
ファイル選択ダイアログが開きます
選択するファイルの拡張子を指定したい場合はサンプルのようにフィルターに値を指定することができます

ダイアログは他にも「色」「フォント」を用意しています

# フォルダ選択ダイアログ
フォルダ選択は古いDelphiに実装されていないので自作しました
ListViewEditDialogFolderを追加したあと編集方法に ListViewEditFolderDialogId2を指定するとフォルダ選択になります
1は新しいDelphi用に実装予定です

# クラスの説明
ソースを公開しているので見てもらえるとわかりますがものすごい量です、これでも不要部分をかなり削っています

上位のクラスから説明します
### TListViewEx
標準のTListViewに使いづらい部分や不具合のようなものがあるのでこの継承クラスで改善しています、単体で使うことはありません

### TListViewEdit
標準のTListViewに編集機能を付けています
これに置き換えるだけで編集出来るようになります
サンプルの別タブに用意していますので使って見て下さい
1列目はListItemのCaption、2列目以降はSubstringの値になります

### TListViewEditRtti
標準のTListViewに編集機能を付けてさらに実行時型情報を利用した編集画面を作成、さらにプラグインで編集を拡張出来る用にしたクラスです

実行時型情報関係がどうなっているのか？知りたい人はRTTIと書かれた関数を見ると多分わかりません

# プラグインについて
Delphiにプラグインが実装できないか実装してみたらうまくいったので採用しています、ちょっとしたことでエラーになる可能性も秘めていますので注意して下さい

## プラグインって何？
機能が盛りだくさんなのはわかりますが、ダイアログやフォルダは使わないことがほとんどです
ですがそのために数ファイルの実装が必要なのは面倒ですよね？

なのでユニットを usesで宣言したとき使えるようにしています

## どうやってるの？
プラグインのプログラムのグローバル変数定義の他に、一番下の行に答えが書いてるので見て下さい、わからなければトレースしてください

## プラグインって作れるの？
サンプルを参考にすれば作れます
単にDelphiの生成方法を利用したプラグインなのでマネすれば作れます

# 利用条件
自分のプログラムは全て「**制作者を偽らないのであれば他に何をしても問題ありません**」
商用利用、問題なし（サポートを求めるのは有料ですよ）
改変、むしろ大歓迎
再配布、問題なし
改変したものを再配布、やってもかまわないけど元の方の配布場所とかこことかをリンク貼って
なんならこっちで修正するかスペシャルサンクスにするから同梱させてほしい
難しいことは要相談

# 制作時間
1から作り直して20日で完成した
あとは勉強時間が2年ぐらい
辞書みたいな書籍を解析して実装してます