ユーザー アクションに対する応答をコード エディタでコーディングする(IDE チュートリアル)
RAD Studio アプリケーションを初めて作成する(IDE チュートリアル):インデックス への移動
このセクションの手順に従うことで、アプリケーションは対話型になり、必要な機能が用意されます。
ここでは、イベント ハンドラ(さまざまなメイン メニュー項目のクリックなどのユーザーによる操作に対する応答)をコーディングします。
目次
コーディングに着手する
アプリケーションの実行中に現在開いているテキスト ファイルの名前を保持するのに頻繁に使用する String
型変数を定義するところから、
コーディングに取りかかりましょう。
In Delphi の場合、ステータスバーで コード タブを選択すると、コード エディタが開きます。 コード エディタを使用して、CurrentFile
という String
変数を、interface
部の TTextEditorForm クラスの private セクションで定義します:
C++Builder では、ステータスバーで TextEditorUnit.h タブを選択すると、ユニットのヘッダー ファイルがコード エディタで開かれます。 コード エディタを使用して、CurrentFile
という String
変数を、TTextEditorForm の private
セクションで宣言します。
フォーム デザイナとコード エディタを切り替えるには、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 イベントを使用できます。
- [デザイン]タブを選択して、フォーム デザイナに戻ります。
- [構造]ビューで、フォーム コンポーネント(
TextEditorForm
)を選択します。 - [オブジェクト インスペクタ]で[イベント]タブを開きます。
- [イベント]タブで、OnCreate イベントの値フィールドをダブルクリックします。RAD Studio により、コード エディタに切り替わり、新しいイベント ハンドラのスケルトン定義が追加されます。そのイベント ハンドラを使用して、既に実装した
UpdateStatusBar
手続きを次のように呼び出します。
procedure TTextEditorForm.FormCreate(Sender: TObject);
begin
Editor.Lines.Add('');
UpdateStatusBar;
end;
void __fastcall TTextEditorForm::FormCreate(TObject *Sender)
{
TextEditorForm->Editor->Lines->Add(L"");
UpdateStatusBar();
}
このコードでは UpdateStatusBar
を呼び出す前に TMemo コンポーネントに空行を 1 つ追加していることに注意してください。それによりメモの行数が初期化されるため、ステータス バーの行数ラベルには最初から "0" ではなく "1" が表示されます。
以下のように、TMemo コンポーネント(Editor
)の OnKeyUp イベントと OnMouseUp イベントについても、上記の手順を繰り返します。
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
を選択します。
そのあと、[オブジェクト インスペクタ]の[イベント]タブを選択し、OnExecute
イベントに対応する編集ボックスをダブルクリックします。コード エディタが開き、そこに新しいイベント ハンドラのスケルトンが表示されます。このイベント ハンドラに、ユーザーが[File|New]を選択したときに実行されるコードを書きます。
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;
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]メニュー項目で使用される残りのアクション OpenAction
、SaveAction
、SaveAsAction
、ExitAction
について同じ手順を繰り返します。以下は、これらの各アクションの OnExecute イベントのイベント ハンドラを実装したものです。
// 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;
// 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
を呼び出します。
// 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;
// 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();
}