Delphi Starter Edition でメモ帳クローンを作る - 番外編

# begin { はじめに
昨年末の [Delphi Advent Calendar 2017](https://qiita.com/advent-calendar/2017/delphi) において、**Delphi Starter Edition でメモ帳クローンを作る**って記事を書きました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/21785/a50ddb1a-fa6d-ba3f-8d6a-07031cb38a77.png)

 - [Delphi Starter Edition でメモ帳クローンを作る (前編)](https://qiita.com/ht_deko/items/bd854e8a22cf31b636b0)
 - [Delphi Starter Edition でメモ帳クローンを作る (後編)](https://qiita.com/ht_deko/items/d5c4de7d55eebca928e2)
 - [Delphi Starter Edition でメモ帳クローンを作る - 2nd Edition -](https://qiita.com/ht_deko/items/525cd67aaba16681c3ba)

そしてこんな記事を見つけました。

 - [【Windows裏ワザ】4文字入力するだけで［メモ帳］が便利になるって知ってた？ (できるネット)](https://dekiru.net/article/16543/)

へぇぇ！そうなんだ！！...という事でこの機能を追加してみたいと思います。

# 実装

## 前回までのソースコードのダウンロード
[前回](https://qiita.com/ht_deko/items/525cd67aaba16681c3ba)終了時点のソースコードは以下から DL できます。

 - https://ht-deko.com/software/notepad_clone.zip

## リファクタリング

ファイルを読み込んでいる場所が 3 箇所ありますので、これを一つにまとめます。

```pascal:frmuMain.pas
  ...

  // キャプションを変更
  UpdateCaption;
  // エンコーディングを指定して読み込み
  Memo1.Lines.LoadFromFile(FFileName, GetEditorEncoding);

  ...
```

まずクラスの定義部に LoadFromFile() というメソッドを作ります。

```pascal:frmuMain.pas
  ...

  private
    { Private 宣言 }
    FFileName: String;
    FEncodingIndex: Integer;
    FHeaderStr: string;
    FFooterStr: string;
    FMarginTop: Integer;
    FMarginBottom: Integer;
    FMarginLeft: Integer;
    FMarginRight: Integer;
    function DetectEncodingFromFile(FileName: string): Integer;
    procedure DispRowCol;
    function GetEditorEncoding: TEncoding;
    function GetTextFileName: string;
    procedure Init(AFileName: string = '');
    procedure LoadFromFile; // <- 追加
    procedure PrintText(const HeaderStr, FooterStr: string);
    procedure SaveFile;
    procedure UpdateCaption;
    procedure WmDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES;
  public
    { Public 宣言 }
  end;
  ...
```

実装部は以下のようになります。**implementation** より下に記述します。

```pascal:frmuMain.pas
procedure TForm1.LoadFromFile;
begin
  // キャプションを変更
  UpdateCaption;
  // エンコーディングを指定して読み込み
  Memo1.Lines.LoadFromFile(FFileName, GetEditorEncoding);
end;
```

そして Memo1.Lines.LoadFromFile() になっている箇所を、この LoadFromFile() で置き換えます。まずは WmDropFiles() メッセージハンドラの中。

```pascal:frmuMain.pas
procedure TForm1.WmDropFiles(var Msg: TWMDropFiles);
var
  Buf: array [0..MAX_PATH] of Char;
begin
  // ドロップされた (最初の) ファイル名を取得
  DragQueryFile(Msg.Drop, 0, Buf, MAX_PATH);
  DragFinish(Msg.Drop);
  // ファイル名を保存
  FFileName := StrPas(Buf);
  // エンコーディングを判定
  FEncodingIndex := DetectEncodingFromFile(FFileName);
  // ファイルを読み込み
  LoadFromFile; // 修正
end;
```

FormShow() イベントハンドラの中。

```pascal:frmuMain.pas
procedure TForm1.FormShow(Sender: TObject);
// フォーム表示時
var
  FileName, Msg: string;
  ret: Integer;
  reg: TRegistryIniFile;
begin
  ...

  FileName := ParamStr(1);
  if TFile.Exists(FileName) then
    begin
      // ファイルが存在する
      FFileName := FileName;
      // エンコーディングを判定
      FEncodingIndex := DetectEncodingFromFile(FFileName);
      // ファイルを読み込み
      LoadFromFile; // 修正
    end
  else
    begin

    ...
```
acOpenExecute() イベントハンドラの中。

```pascal:frmuMain.pas
procedure TForm1.acOpenExecute(Sender: TObject);
// Action: 開く(O)...
begin
  OpenTextFileDialog1.EncodingIndex := FEncodingIndex;
  if OpenTextFileDialog1.Execute then
    begin
      // 値を保存
      FFileName := OpenTextFileDialog1.FileName;
      FEncodingIndex := OpenTextFileDialog1.EncodingIndex;
      // ファイルを読み込み
      LoadFromFile; // 修正
    end;
end;
```

これでリファクタリングは完了です。ファイルを開くロジックが一箇所に集約されました。

## 日付挿入ロジックの追加

日付挿入ロジックは以下のようになります。

 1. ファイルを読み取ってみる。
 2. 先頭行が ".LOG" で始まっていれば日付文字列 + 改行を追加

先頭行が ".LOG" というのは大文字で .LOG から始まっているという意味で、小文字ではダメですが、.LOGCABIN は受け付けます。星を散りばめた甘い夜を今も思い出しますね (?)。

先頭行は Memo1 (TMemo) の [Lines](http://docwiki.embarcadero.com/Libraries/ja/Vcl.StdCtrls.TCustomMemo.Lines) プロパティの最初の要素です。つまり Memo1.Lines[0] が先頭行の文字列となります。これを調べればいいのですが、Memo1 が空の場合にはアクセスできません。つまり、まずは最低でも一行存在するかどうかを判定しなくてはなりません。Memo1 の行数は [Lines.Count](http://docwiki.embarcadero.com/Libraries/ja/System.Classes.TStrings.Count) プロパティで調べられます。

```pascal
  if Memo1.Lines.Count > 0 then
    begin
      // ここに処理
    end;
```
先頭行が ".LOG" で始まっているかどうかは、[System.Pos()](http://docwiki.embarcadero.com/Libraries/ja/System.Pos) 関数で調べられます。[System.Pos()](http://docwiki.embarcadero.com/Libraries/ja/System.Pos) は大文字小文字を区別します。単純な比較なので、正規表現を使うまでもないでしょう。

```pascal
  if Pos('.LOG', Memo1.Lines[0]) = 1 then
    begin
      // ここに処理
    end;
```

TMemo の末尾に行を追加するには、[Lines.Add()](http://docwiki.embarcadero.com/Libraries/ja/System.Classes.TStrings.Add) メソッドを使います。以下のコードは Memo1 の末尾に 'ABC' という行を追加します。

```pascal
  Memo1.Lines.Add('ABC');
```

これらを踏まえると、LoadFromFile() メソッドの中身はこうなります。

```pascal:frmuMain.pas
procedure TForm1.LoadFromFile;
begin
  // キャプションを変更
  UpdateCaption;
  // エンコーディングを指定して読み込み
  Memo1.Lines.LoadFromFile(FFileName, GetEditorEncoding);
  // 日付の追加
  if (Memo1.Lines.Count > 0) and (Pos('.LOG', Memo1.Lines[0]) = 1) then
    begin
      Memo1.Lines.Add(FormatDateTime('hh:nn yyyy/mm/dd', Now));
      Memo1.Lines.Add('');
    end;
end;
```

# おわりに } end.
小改造なのでプロパティやメソッドを知っていれば簡単でしたね。

Delphi Starter Edition は現在 10.2 Tokyo Release 3 (10.2.3) がリリースされています。無償でアップデートできますので、Starter Edition をお使いの方は是非アップデートしてみてください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/21785/bab357b0-6841-d32a-ed73-6735e846039a.png)

新規インストールすると最初から 10.2.3 となります。

**See also:**

 - [Delphi Starter Edition (Embarcadero)](https://www.embarcadero.com/jp/products/delphi/starter)
 - [Starter Edition ユーザーのための Delphi / C++Builder 10.2 Tokyo Starter Edition (無償！) 入手ガイド](https://community.embarcadero.com/blogs/entry/starter-edition-delphi-c-builder-10-2-tokyo-starter-edition-japan)
 - [金曜日のライオン (Take it to the lucky) - TM Network (Amazon Music)](https://www.amazon.co.jp/dp/B00FSB8MV0/)