2026/01/13(火) [n年前の日記]
#1 [delphi] Delphi 12を勉強中
せっかく Delphi 12 をインストールしたので勉強中。
◎ JSONの解析でハマった :
Delphi もC#と同様に、サイズが可変する配列っぽい TList<T> なるものがあるようで助かった。
さておき、TList<T> を含んだクラスをJSONにして保存して、そのJSONを読み込んでクラスにしようとしたのだけど…。
AIに尋ねたら REST.Json だの TJson.JsonToObject<T> だのを薦められて、それを使って処理できないかと数時間ほど試してたのだけど…。構造体に相当するのであろう record だの、可変配列っぽい TList<T> だのを復元できなくてエラーが発生してしまって解決できなくて…。
TJsonSerializer を使ったらあっさり復元できた…。System.JSON.Serializers が必要。System.JSON.Types もあるといい。読みやすいJSONに変換してくれる。uses のあたりに、以下のように書いた。
TContainer というクラスの内容をJSON化してファイルに保存する例。
SL.Formatting := TJsonFormatting.Indented; を指定すると人間でも読みやすいJSONにしてくれる。
JSONファイルを読み込んで TContainer というクラスに内容を反映する例。
さておき、TList<T> を含んだクラスをJSONにして保存して、そのJSONを読み込んでクラスにしようとしたのだけど…。
AIに尋ねたら REST.Json だの TJson.JsonToObject<T> だのを薦められて、それを使って処理できないかと数時間ほど試してたのだけど…。構造体に相当するのであろう record だの、可変配列っぽい TList<T> だのを復元できなくてエラーが発生してしまって解決できなくて…。
TJsonSerializer を使ったらあっさり復元できた…。System.JSON.Serializers が必要。System.JSON.Types もあるといい。読みやすいJSONに変換してくれる。uses のあたりに、以下のように書いた。
uses System.SysUtils, System.IOUtils, System.Generics.Collections, System.JSON.Serializers, System.JSON.Types;
TContainer というクラスの内容をJSON化してファイルに保存する例。
procedure SaveContainerToFile(const FileName: string; Container: TContainer);
var
SL: TJsonSerializer;
json: string;
begin
SL := TJsonSerializer.Create;
SL.Formatting := TJsonFormatting.Indented;
try
json := SL.Serialize(Container);
TFile.WriteAllText(FileName, json, TEncoding.UTF8);
finally
SL.Free;
end;
end;
SL.Formatting := TJsonFormatting.Indented; を指定すると人間でも読みやすいJSONにしてくれる。
JSONファイルを読み込んで TContainer というクラスに内容を反映する例。
function LoadContainerFromFile(const FileName: string): TContainer;
var
SL: TJsonSerializer;
json: string;
begin
json := TFile.ReadAllText(FileName, TEncoding.UTF8);
SL := TJsonSerializer.Create;
try
Result := SL.Deserialize<TContainer>(json);
finally
SL.Free;
end;
end;
◎ フォームを表示する前に処理をしたい :
Delphiを使って、まずはスクリーンセーバを作れないものかと試している。
フルスクリーン表示用フォーム、設定画面モード用フォーム、プレビュー画面モード用フォームの3つのフォームを作って、与えられたコマンドライン引数に応じてどれかしらのフォームを表示するようにしてみたい。
フォームの追加は、ファイル → 新規作成 → VCLフォーム - Delphi、を選べばできる模様。たぶん。
ただ、プロジェクトを新規作成した際に用意されているフォームを表示してしまうその前に、コマンドライン引数を解析しないといけない。どうすれば…。
プロジェクト → ソースの表示、を選ぶか、もしくは右側のプロジェクト名が表示されてるところを右クリックしてソースの表示を選べば、一番最初に呼ばれる処理が書かれてるソースが表示できると分かった。拡張子は .dpr。.pasじゃないんだ…。このファイルが、C# で言うところの Program.cs に相当するのではないか。たぶん。
中身は以下のような感じだった。
Application.CreateForm(TForm1, Form1); でフォームを生成して、Application.Run; でイベント待ちのループになるのかな…。たぶん。
ということは、Application.CreateForm(TForm1, Form1); を呼ぶ前に引数の解析処理をして、そこからどのフォームを生成するか決めればいいのではないか…。
試してみたら期待した動作になった。引数の与え方で、3つのフォームを呼び分けることができた。
コマンドライン引数の数や文字列は、ParamCount、ParamStr(n) で取得できる。ParamStr(0) に .exe名が入っていて、引数は ParamStr(1)、ParamStr(2)、ParamStr(3) 等に入ってる。
フルスクリーン表示用フォーム、設定画面モード用フォーム、プレビュー画面モード用フォームの3つのフォームを作って、与えられたコマンドライン引数に応じてどれかしらのフォームを表示するようにしてみたい。
フォームの追加は、ファイル → 新規作成 → VCLフォーム - Delphi、を選べばできる模様。たぶん。
ただ、プロジェクトを新規作成した際に用意されているフォームを表示してしまうその前に、コマンドライン引数を解析しないといけない。どうすれば…。
プロジェクト → ソースの表示、を選ぶか、もしくは右側のプロジェクト名が表示されてるところを右クリックしてソースの表示を選べば、一番最初に呼ばれる処理が書かれてるソースが表示できると分かった。拡張子は .dpr。.pasじゃないんだ…。このファイルが、C# で言うところの Program.cs に相当するのではないか。たぶん。
中身は以下のような感じだった。
program HelloWorldDelphi;
uses
Vcl.Forms,
HelloWorldVCL1 in 'HelloWorldVCL1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Application.CreateForm(TForm1, Form1); でフォームを生成して、Application.Run; でイベント待ちのループになるのかな…。たぶん。
ということは、Application.CreateForm(TForm1, Form1); を呼ぶ前に引数の解析処理をして、そこからどのフォームを生成するか決めればいいのではないか…。
試してみたら期待した動作になった。引数の与え方で、3つのフォームを呼び分けることができた。
コマンドライン引数の数や文字列は、ParamCount、ParamStr(n) で取得できる。ParamStr(0) に .exe名が入っていて、引数は ParamStr(1)、ParamStr(2)、ParamStr(3) 等に入ってる。
◎ 余談。Pascalの印象 :
Delphi はDelphi言語なるプログラミング言語らしいけど、元々はPascalという言語らしくて…。初めて触ってるけれど、今まで触ってきた言語とはなんだかちょっと違うなと…。
細かいことだけど、変数への代入が「=」じゃなくて「:=」なので地味にツラい。ついつい「=」と打ってしまう。数学的には「:=」と記述するほうが正しいのかもしれないけれど…。
_変数を使う
_代入あれこれ
たしかに、比較演算子で「==」と書くべきところを「=」と書いてしまってバグを入れてしまうミスは避けられるか…。その代わり、フツーの言語なら「=」の1文字で済むのに、わざわざ「:=」の2文字を打たないといけない。打鍵数が増える…。
変数を確保、というか宣言する際に、最初のあたりに書かないといけないのも面倒。欲しくなったらその場で確保させてくれよ…。ループを回すだけの変数すらあらかじめ用意しないといけないのはシンドイ…。
begin と end が多過ぎてゲンナリする…。お前は Ruby か! この begin-end 野郎!(意味不明)。いや、Ruby で多過ぎと言われてるのは end だけだったような…? 始まりと終わりを示すだけなら () でも {} でも [] でもええやん…。でも記号を多用するとそれが何を意味してるのか分かりづらくなるデメリットもあるのかな。Perlになっちゃう…。
文字列は '' で記述しないとダメっぽい。"" に慣れてるので、つい "" を打って怒られる…。
そんな感じであちこちしっくりこないけど、その代わり(?)、コンパイルは爆速。サクサクと動作確認できる。この速さは素晴らしい。
これは Pascal云々ではなくて Delphi の長所だろうけど、生成される .exe も数MBと小さい。C# で作ったアプリは100MB以上になるので、ファイルサイズの桁が違う…。
細かいことだけど、変数への代入が「=」じゃなくて「:=」なので地味にツラい。ついつい「=」と打ってしまう。数学的には「:=」と記述するほうが正しいのかもしれないけれど…。
_変数を使う
_代入あれこれ
たしかに、比較演算子で「==」と書くべきところを「=」と書いてしまってバグを入れてしまうミスは避けられるか…。その代わり、フツーの言語なら「=」の1文字で済むのに、わざわざ「:=」の2文字を打たないといけない。打鍵数が増える…。
変数を確保、というか宣言する際に、最初のあたりに書かないといけないのも面倒。欲しくなったらその場で確保させてくれよ…。ループを回すだけの変数すらあらかじめ用意しないといけないのはシンドイ…。
begin と end が多過ぎてゲンナリする…。お前は Ruby か! この begin-end 野郎!(意味不明)。いや、Ruby で多過ぎと言われてるのは end だけだったような…? 始まりと終わりを示すだけなら () でも {} でも [] でもええやん…。でも記号を多用するとそれが何を意味してるのか分かりづらくなるデメリットもあるのかな。Perlになっちゃう…。
文字列は '' で記述しないとダメっぽい。"" に慣れてるので、つい "" を打って怒られる…。
そんな感じであちこちしっくりこないけど、その代わり(?)、コンパイルは爆速。サクサクと動作確認できる。この速さは素晴らしい。
これは Pascal云々ではなくて Delphi の長所だろうけど、生成される .exe も数MBと小さい。C# で作ったアプリは100MB以上になるので、ファイルサイズの桁が違う…。
[ ツッコむ ]
以上です。