Delphiのフォーマッタ(コードの整形)でDataMoudleが壊れる

TDataMoudleにはClassGroupプロパティがあります。
このプロパティで、データモジュールがVCL用かFMX用かフレームワークに依存しないかを設定します。

たとえばTTimerコンポーネントはVCL用のVcl.ExtCtrls.TTimerとFMX用のFMX.Types.TTimerがあります。
使用するコンポーネントとClassGroupで設定したフレームワークを一致させる必要があります。

formatter01

オブジェクトインスペクタでClassGroupプロパティを設定すると、ユニットファイルには次のような指令が追加されます。

ClassGroupがFMX.Controls.TControlの場合:

{%CLASSGROUP 'FMX.Controls.TControl'}

フォーマッタのコメントスペースの設定の「{ および (* コメントスペースの設定」は初期値が「内側と外側」になっています。
この設定でコードを整形すると、ClassGroupプロパティによって追加された指令が次のようになります。

{ %CLASSGROUP 'FMX.Controls.TControl' }

「{」「}」の間に空白が追加されました。

このように空白が追加されると、ClassGroupプロパティの値は未設定の状態になります。

ClassGroupプロパティの値が設定されていない状態になると、コンポーネントとフレームワークに不一致が生じます。
その結果、IDEでデータモジュールを読み込むときにエラーが発生します。

エラーが発生した場合は、ClassGroupプロパティの指令を修正すれば、元の状態に戻ります。

TMemIniFileに変更があれば自動的に保存する

Delphi 10.1 BerlinではTMemIniFileにAutoSaveプロパティが追加されました。

AutoSaveプロパティがTrueのときは、インスタンスの破棄時に変更があれば自動的に保存されます。

var
  Ini: TMemIniFile;
begin
  Ini := TMemIniFile.Create('C:\temp\test.ini', // ファイル名
    TEncoding.UTF8, // エンコーディング
    True); // セクションとキーの名前の大文字小文字を区別するか
  try
    Ini.AutoSave := True; // 変更があれば自動的に保存する
    …
  finally
    Ini.Free; // 変更があれば自動的に保存されます
  end;
end;

Delphi 10.1 BerlinでDOSCommandコンポーネントを使う

TurboPackDOSCommandコンポーネントは、バッチファイルを実行し、出力された文字を受け取ることができるコンポーネントです。
VCLアプリケーションとFireMonkeyアプリケーションの両方で使用できます。
対応しているOSはWindowsのみです。

DOSCommand-2

GetItに登録されているので、簡単にインストールできます。

DOSCommand-1

コマンドラインを実行する

実行するコマンドラインをCommandLineプロパティに設定して、Executeメソッドでプロセスを実行します。

DosCommand1.CommandLine := 'C:\Users\yamamoto\Documents\dir.bat';
DosCommand1.Execute;

カレントディレクトリを設定するにはCurrentDirプロパティを使用します。

DosCommand1.CurrentDir := 'C:\Users\yamamoto\';

出力を取得する

OnNewCharイベントで新しく出力された文字を取得できます。

OnNewLineイベントで出力された行を取得できます。

procedure TForm1.DosCommand1NewLine(ASender: TObject; const ANewLine: string;
  AOutputType: TOutputType);
begin
  case AOutputType of
    otEntireLine:
      Memo1.Lines.Add(ANewLine);
  end;
end;

memoやricheditに出力を直接渡したいときは、OutputLinesプロパティを使います。

DosCommand1.OutputLnes := Memo1.Lines;

Linesプロパティでコマンドのすべての出力を取得できます。

Memo2.Lines.AddStrings(DosCommand1.Lines);

入力を送信する

SendLine関数でDOSプロセスに入力を送信できます。

DosCommand1.SendLine('', True);

プロセスを中止する

OnTerminatedイベントでコマンドの終了を取得できます。

procedure TForm1.DosCommand1Terminated(Sender: TObject);
begin
  Memo1.Lines.Add('終了しました。');
end;

プロセスが終わる前に止めたいときは、Stopメソッドを使います。
※未確認

X秒間実行した後にプロセスを止めたいときは、MaxTimeAfterBeginningプロパティを使います。
※未確認

X秒間出力がなければプロセスを止めたい場合は、MaxTimeAfterLastOutputプロパティを使います。
※未確認

その他の設定

Priorityプロパティでプロセスの優先度を変更できます。

uses Winapi.Windows;

DosCommand1.Priority := HIGH_PRIORITY_CLASS;

優先度には次の値を設定します。

  • HIGH_PRIORITY_CLASS
  • IDLE_PRIORITY_CLASS
  • NORMAL_PRIORITY_CLASS
  • REALTIME_PRIORITY_CLASS

TerminatedプロパティがTrueのとき、入力された文字を出力します。
※未確認

サンプルアプリケーション

フォームにTDosCommandコンポーネントと、TButtonコンポーネント、TMemoコンポーネントを配置します。

DOSCommand-3

Button1を押すと、カレントディレクトリを「C:\Users\yamamoto\」にして、バッチファイル「C:\Users\yamamoto\Documents\dir.bat」を実行します。

出力された内容ははMemo1に表示します。

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Clear;
  DosCommand1.CurrentDir := 'C:\Users\yamamoto\';
  DosCommand1.CommandLine := 'C:\Users\yamamoto\Documents\dir.bat';
  DosCommand1.Execute;
end;

procedure TForm1.DosCommand1NewLine(ASender: TObject; const ANewLine: string;
  AOutputType: TOutputType);
begin
  // 出力された文字を1行ずつ受け取る
  case AOutputType of
    otEntireLine:
      Memo1.Lines.Add(ANewLine);
  end;
end;

procedure TForm1.DosCommand1Terminated(Sender: TObject);
begin
  Memo1.Lines.Add('終了しました。');
end;

TStringListの要素を文字列の長さでソートする

DelphiのTStringListには、リスト内の文字列を昇順でソートするSortメソッドの他に、任意の条件でソートするCustomSortメソッドがあります。
TStringListのCustomSortメソッドを使って、文字列の長さでソートする方法を紹介します。

CustomSortメソッドは引数にTStringListSortCompare型の関数をとります。
TStringListSortCompare型は次のように定義されています。

TStringListSortCompare = function(List: TStringList; Index1, Index2: Integer): Integer;

TStringListSortCompare型の文字列の長さを比較する関数を作成します。

function StringLengthCompare(List: TStringList; Index1, Index2: Integer): Integer;
begin
  Result := List[Index1].Length - List[Index2].Length;
end;

TStringListのCustomSortメソッドの引数にこの関数を渡すと、文字列の長さ順にソートします。

次のサンプルアプリケーションでは、ボタンを押すとTStringListの文字列をソートして結果をメモに表示します。

フォームにTButtonとTMemoを配置します。
ボタンを押すと、ソート結果を表示します。

function StringLengthCompare(List: TStringList; Index1, Index2: Integer): Integer;
begin
  Result := List[Index1].Length - List[Index2].Length;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  stli: TStringList;
begin
  stli := TStringList.Create;

  // お試しデータ格納
  stli.Add('aa');
  stli.Add('a');
  stli.Add('aaaaa');
  stli.Add('aaaa');
  stli.Add('aaa');

  stli.CustomSort(StringLengthCompare);
  Memo1.Text := stli.Text;

  stli.Free;
end;

sort01