ユーザー アクションに対する応答をコード エディタでコーディングする(IDE チュートリアル)

提供: RAD Studio
移動先: 案内検索

RAD Studio アプリケーションを初めて作成する(IDE チュートリアル):インデックス への移動


このセクションの手順に従うことで、アプリケーションは対話型になり、必要な機能が用意されます。

ここでは、イベント ハンドラ(さまざまなメイン メニュー項目のクリックなどのユーザーによる操作に対する応答)をコーディングします。

コーディングに着手する

アプリケーションの実行中に現在開いているテキスト ファイルの名前を保持するのに頻繁に使用する String 型変数を定義するところから、

コーディングに取りかかりましょう。

In Delphi の場合、ステータスバーで コード タブを選択すると、コード エディタが開きます。 コード エディタを使用して、CurrentFile という String 変数を、interface 部の TTextEditorForm クラスの private セクションで定義します:

TutorialIDENewFig3-18kh2.PNG
private 変数 CurrentFile の定義(Delphi での表示

C++Builder では、ステータスバーで TextEditorUnit.h タブを選択すると、ユニットのヘッダー ファイルがコード エディタで開かれます。 コード エディタを使用して、CurrentFile という String 変数を、TTextEditorFormprivate セクションで宣言します。

TutorialIDENewFig3-19kh.PNG
private 変数 CurrentFile の定義(C++Builder での表示)

フォーム デザイナコード エディタを切り替えるには、F12 キーを押します。

テキスト エディタでのアクションに対する応答でステータス バーを更新する

ユーザーがキャレット(テキスト カーソル)を動かしたり、TMemo コンポーネントのコンテンツを変更した場合は、ステータス バーを更新する必要があります。さまざまなイベントに対する応答でステータス バーを更新する必要があるため、コードに単一の手続きを定義し、後で、ステータス バーの更新を必要とするあらゆるイベント ハンドラからその手続きを呼び出すことができます。

Delphi の場合、アプリケーションにこの新しい手続きを定義するには、interface 部の TTextEditorForm クラスの private セクションで、先ほど定義した CurrentFile 変数のすぐ下に次のようなプロシージャのシグネチャを追加します:

procedure UpdateStatusBar;

コードで UpdateStatusBar を右クリックし、[カーソル位置のクラスを補完]を選択すると、RAD Studio が、そのプロシージャのスケルトン定義を、コードの implementation 部に追加します:

procedure TTextEditorForm.UpdateStatusBar;
begin

end;

UpdateStatusBar プロシージャのロジックを上記の begin キーワードと end キーワードの間に次のように定義します:

LineNumber.Text := 'L: ' + (Editor.CaretPosition.Line+1).ToString;
ColumnNumber.Text := 'C: ' + (Editor.CaretPosition.Pos+1).ToString;
LineCount.Text := 'Lines: ' + Editor.Lines.Count.ToString;

C++ の場合、アプリケーションにこの新しい関数を定義するには、TextEditorUnit.h ファイル内の TTextEditorForm クラスの private セクションで、先ほど定義した CurrentFile 変数のすぐ下に次のような関数シグネチャを追加します。

void UpdateStatusBar();

実装ファイル TextEditorUnit.cpp を選択し、この関数を次のように実装します。

void TTextEditorForm::UpdateStatusBar()
{
    TextEditorForm->LineNumber->Text = L"L: " + String(TextEditorForm->Editor->CaretPosition.Line+1);
    TextEditorForm->ColumnNumber->Text = L"C: " + String(TextEditorForm->Editor->CaretPosition.Pos+1);
    TextEditorForm->LineCount->Text = L"Lines: " + String(TextEditorForm->Editor->Lines->Count);
}

これで、任意のイベント ハンドラから UpdateStatusBar を呼び出して、ステータス バーを更新することができます。

ステータス バーに表示される情報を初めて更新しなければならないのは、アプリケーションの起動時です。それには、以下のように、フォームの OnCreate イベントを使用できます。

  1. [デザイン]タブを選択して、フォーム デザイナに戻ります。
  2. [構造]ビューで、フォーム コンポーネント(TextEditorForm)を選択します。
  3. [オブジェクト インスペクタ][イベント]タブを開きます。
  4. [イベント]タブで、OnCreate イベントの値フィールドをダブルクリックします。RAD Studio により、コード エディタに切り替わり、新しいイベント ハンドラのスケルトン定義が追加されます。そのイベント ハンドラを使用して、既に実装した UpdateStatusBar 手続きを次のように呼び出します。
Delphi の場合:
procedure TTextEditorForm.FormCreate(Sender: TObject);
begin
  Editor.Lines.Add('');
  UpdateStatusBar;
end;
C++ の場合:
void __fastcall TTextEditorForm::FormCreate(TObject *Sender)
{
        TextEditorForm->Editor->Lines->Add(L"");
        UpdateStatusBar();
}

このコードでは UpdateStatusBar を呼び出す前に TMemo コンポーネントに空行を 1 つ追加していることに注意してください。それによりメモの行数が初期化されるため、ステータス バーの行数ラベルには最初から "0" ではなく "1" が表示されます。

以下のように、TMemo コンポーネント(Editor)の OnKeyUp イベントと OnMouseUp イベントについても、上記の手順を繰り返します。

Delphi の場合:
procedure TTextEditorForm.EditorKeyUp(Sender: TObject; var Key: Word;
  var KeyChar: Char; Shift: TShiftState);
begin
  UpdateStatusBar;
end;

procedure TTextEditorForm.EditorMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  UpdateStatusBar;
end;

C++ の場合:

void __fastcall TTextEditorForm::EditorKeyUp(TObject *Sender, WORD &Key, System::WideChar &KeyChar,
          TShiftState Shift)
{
    UpdateStatusBar();
}

void __fastcall TTextEditorForm::EditorMouseUp(TObject *Sender, TMouseButton Button,
          TShiftState Shift, float X, float Y)
{
    UpdateStatusBar();
}

[File]メニュー項目のイベント ハンドラを作成する

メニュー項目のクリックに対する応答を定義する準備ができました。フォーム デザイナが開いた状態で、下図のように、[構造]ビューで NewAction を選択します。

IDETutorialSelectingNewAction.png

そのあと、[オブジェクト インスペクタ][イベント]タブを選択し、OnExecute イベントに対応する編集ボックスをダブルクリックします。コード エディタが開き、そこに新しいイベント ハンドラのスケルトンが表示されます。このイベント ハンドラに、ユーザーが[File|New]を選択したときに実行されるコードを書きます。

Delphi の場合:
procedure TTextEditorForm.NewActionExecute(Sender: TObject);
var
  UserResponse: Integer;
begin
  // Ask for confirmation if the memo is not empty.
  if not Editor.Text.IsEmpty then
  begin
    UserResponse := TDialogServiceSync.MessageDialog(
      'This will clear the current document. Do you want to continue?',
      TMsgDlgType.mtInformation, mbYesNo, TMsgDlgBtn.mbYes, 0);
    if UserResponse = mrYes then
    begin
      Editor.Text := '';
      Editor.Lines.Add(''); // Initialize the memo line count to "1".
      UpdateStatusBar;
      CurrentFile := ''; // New files have no file name until saved.
    end;
  end;
end;
C++ の場合:
void __fastcall TTextEditorForm::NewActionExecute(TObject *Sender)
{
    if (!TextEditorForm->Editor->Text.IsEmpty()) {
        int UserResponse = TDialogServiceSync::MessageDialog(
            L"This will clear the current document. Do you want to continue?",
            TMsgDlgType::mtInformation, mbYesNo, TMsgDlgBtn::mbYes, 0);
        if (UserResponse == mrYes) {
            TextEditorForm->Editor->Text = L"";
            TextEditorForm->Editor->Lines->Add(L"");  // Initialize the memo line count to "1".
            UpdateStatusBar();
            CurrentFile = L"";  // New files have no file name until saved.
        }
    }
}

[デザイン]タブをクリックしてフォーム デザイナに戻り、[File]メニュー項目で使用される残りのアクション OpenActionSaveActionSaveAsActionExitAction について同じ手順を繰り返します。以下は、これらの各アクションの OnExecute イベントのイベント ハンドラを実装したものです。

Delphi の場合:
// File > Open
procedure TTextEditorForm.OpenActionExecute(Sender: TObject);
var
  FileName: String;
begin
  if OpenFileDialog.Execute = True then
  begin
    FileName := OpenFileDialog.FileName;
    if FileExists(FileName) then
    begin
      Editor.Lines.LoadFromFile(FileName);
      CurrentFile := FileName;
      Caption := 'Text Editor - ' + ExtractFileName(FileName);
    end;
  end;
end;

// File > Save
procedure TTextEditorForm.SaveActionExecute(Sender: TObject);
begin
  if CurrentFile = '' then
    SaveAsAction.Execute()
  else
    Editor.Lines.SaveToFile(CurrentFile);
end;

// File > Save As
procedure TTextEditorForm.SaveAsActionExecute(Sender: TObject);
var
  FileName: String;
  UserResponse: TModalResult;
begin
  if SaveFileDialog.Execute = True then
  begin
    FileName := SaveFileDialog.FileName;
    if FileExists(FileName) then
    begin
      UserResponse := TDialogServiceSync.MessageDialog(
        'File already exists. Do you want to overwrite?',
        TMsgDlgType.mtInformation, mbYesNo, TMsgDlgBtn.mbYes, 0);
      if UserResponse = mrNo then
        Exit;
    end;
    Editor.Lines.SaveToFile(FileName);
    CurrentFile := FileName;
    Caption := 'Text Editor - ' + ExtractFileName(FileName);
  end;
end;

// File > Exit
procedure TTextEditorForm.ExitActionExecute(Sender: TObject);
begin
  Application.Terminate;
end;
C++ の場合:
// File > Open
void __fastcall TTextEditorForm::OpenActionExecute(TObject *Sender)
{
    if (TextEditorForm->OpenFileDialog->Execute()) {
        String FileName = TextEditorForm->OpenFileDialog->FileName;
        if (FileExists(FileName)) {
            TextEditorForm->Editor->Lines->LoadFromFile(FileName);
            CurrentFile = FileName;
            Caption = L"Text Editor - " + ExtractFileName(FileName);
        }
    }
}

// File > Save
void __fastcall TTextEditorForm::SaveActionExecute(TObject *Sender)
{
    if (CurrentFile == L"") {
        TextEditorForm->SaveAsAction->Execute();
    } else {
        TextEditorForm->Editor->Lines->SaveToFile(CurrentFile);
    }
}

// File > Save As
void __fastcall TTextEditorForm::SaveAsActionExecute(TObject *Sender)
{
    if (TextEditorForm->SaveFileDialog->Execute()) {
        String FileName = TextEditorForm->SaveFileDialog->FileName;
        if (FileExists(FileName)) {
            String UserResponse = TDialogServiceSync::MessageDialog(
                L"File already exists. Do you want to overwrite?",
                TMsgDlgType::mtInformation, mbYesNo, TMsgDlgBtn::mbYes, 0);
            if (UserResponse == System::Uitypes::TMsgDlgBtn::mbNo) {
                return;
            }
        }
        TextEditorForm->Editor->Lines->SaveToFile(FileName);
        CurrentFile = FileName;
        Caption = L"Text Editor - " + ExtractFileName(FileName);
    }
}

// File > Exit
void __fastcall TTextEditorForm::ExitActionExecute(TObject *Sender)
{
    Application->Terminate();
}

[Edit]および[Format]メニュー項目のイベント ハンドラを作成する

[Edit]メニューと[Format]メニューのメニュー項目のアクションを実装するには、[File]メニューのアクションの場合と同じ手順に従う必要があります。これらのイベント ハンドラは非常に簡単です。つまり、必要な機能はすべて TMemo クラスに既に実装されているので、イベント ハンドラではアクションをメモ コンポーネントに転送するだけであり、アクションの結果、キャレット位置のコンテンツや行数に何らかの影響が生じる可能性がある場合は、イベント ハンドラから UpdateStatusBar を呼び出します。

Delphi の場合:
// Edit > Cut
procedure TTextEditorForm.CutActionExecute(Sender: TObject);
begin
  Editor.CutToClipboard;
  UpdateStatusBar;
end;

// Edit > Copy
procedure TTextEditorForm.CopyActionExecute(Sender: TObject);
begin
  Editor.CopyToClipboard;
end;

// Edit > Paste
procedure TTextEditorForm.PasteActionExecute(Sender: TObject);
begin
  Editor.PasteFromClipboard;
  UpdateStatusBar;
end;

// Edit > Select All
procedure TTextEditorForm.SelectAllActionExecute(Sender: TObject);
begin
  Editor.SelectAll;
  UpdateStatusBar;
end;

// Edit > Undo
procedure TTextEditorForm.UndoActionExecute(Sender: TObject);
begin
  Editor.UnDo;
  UpdateStatusBar;
end;

// Edit > Delete
procedure TTextEditorForm.DeleteActionExecute(Sender: TObject);
begin
  if Editor.SelLength > 0 then
    Editor.DeleteSelection
  else
    Editor.DeleteFrom(Editor.CaretPosition, 1, [TDeleteOption.MoveCaret]);
  UpdateStatusBar;
end;

// Format > Word Wrap
procedure TTextEditorForm.WordWrapActionExecute(Sender: TObject);
begin
  Editor.WordWrap := not Editor.WordWrap;
  WordWrapAction.Checked := Editor.WordWrap;
  UpdateStatusBar;
end;
C++ の場合:
// Edit > Cut
void __fastcall TTextEditorForm::CutActionExecute(TObject *Sender)
{
    TextEditorForm->Editor->CutToClipboard();
    UpdateStatusBar();
}

// Edit > Copy
void __fastcall TTextEditorForm::CopyActionExecute(TObject *Sender)
{
    TextEditorForm->Editor->CopyToClipboard();
}

// Edit > Paste
void __fastcall TTextEditorForm::PasteActionExecute(TObject *Sender)
{
    TextEditorForm->Editor->PasteFromClipboard();
    UpdateStatusBar();
}

// Edit > Select All
void __fastcall TTextEditorForm::SelectAllActionExecute(TObject *Sender)
{
    TextEditorForm->Editor->SelectAll();
    UpdateStatusBar();
}

// Edit > Undo
void __fastcall TTextEditorForm::UndoActionExecute(TObject *Sender)
{
    TextEditorForm->Editor->UnDo();
    UpdateStatusBar();
}

// Edit > Delete
void __fastcall TTextEditorForm::DeleteActionExecute(TObject *Sender)
{
    if (TextEditorForm->Editor->SelLength > 0) {
        TextEditorForm->Editor->DeleteSelection();
    } else {
        TextEditorForm->Editor->DeleteFrom(
            TextEditorForm->Editor->CaretPosition, 1,
            Fmx::Memo::TDeleteOptions() << Fmx::Memo::TDeleteOption::MoveCaret);
    }
    UpdateStatusBar();
}

// Format > Word Wrap
void __fastcall TTextEditorForm::WordWrapActionExecute(TObject *Sender)
{
    TextEditorForm->Editor->WordWrap = !TextEditorForm->Editor->WordWrap;
    TextEditorForm->WordWrapAction->Checked = TextEditorForm->Editor->WordWrap;
    UpdateStatusBar();
}

次のチュートリアル

アプリケーションをコンパイルして実行する