Programmieren von Reaktionen auf Benutzeraktionen im Quelltext-Editor (IDE-Tutorial)

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Ihre erste Anwendung mit RAD Studio - Index (IDE-Tutorial)


Mithilfe der Anleitungen in diesem Abschnitt gestalten Sie Ihre Anwendung interaktiv und fügen die gewünschte Funktionalität hinzu. In diesem Abschnitt werden die Ereignisbehandlungsroutinen programmiert, d. h. die Reaktionen auf die Auswahl der verschiedenen Einträge im Hauptmenü und auf andere Arten von Benutzerinteraktionen.

Beginnen der Programmierung

Fangen Sie mit der Definition einer String-Variable an, die während der Ausführung der Anwendung den Namen der aktuell geöffneten Textdatei aufnimmt.

Wählen Sie in Delphi in der Statusleiste das Register Code, um den Quelltext-Editor zu öffnen. Verwenden Sie den Quelltext-Editor, um im Abschnitt "private" der Klasse TTextEditorForm eine String-Variable namens CurrentFile und zwar im interface-Teil zu definieren:


Quelltext-Editor für Delphi
Definieren der "private" Variable CurrentFile (Delphi-Ansicht)

Wählen Sie in C++Builder in der Statusleiste das Register TextEditorUnit.h, um die Header-Datei der Unit im Quelltext-Editor zu öffnen. Verwenden Sie Quelltext-Editor, um eine String-Variable namens CurrentFile im private Abschnitt von TTextEditorForm zu deklarieren:

Quelltext-Editor für C++
Definieren der "private" Variable CurrentFile (C++Builder-Ansicht)

Um zwischen dem Formular-Designer und dem Quelltext-Editor zu wechseln, drücken Sie die Taste F12.

Aktualisieren der Statusleiste als Reaktion auf Aktionen im Texteditor

Wenn der Benutzer den Textcursor bewegt oder den Inhalt der TMemo-Komponente ändert, müssen Sie die Statusleiste aktualisieren. Da die Statusleiste als Reaktion auf viele verschiedene Ereignisse aktualisiert werden muss, können Sie eine einzige Prozedur im Code definieren und diese Prozedur dann später von jeder Ereignisbehandlungsroutine aus aufrufen, die die Statusleiste aktualisieren muss.

Fügen Sie in Delphi zum Definieren dieser neuen Prozedur in Ihrer Anwendung die folgende Prozedursignatur dem "private" Abschnitt der Klasse TTextEditorForm hinzu und zwar im interface-Teil direkt unterhalb der Variable CurrentFile, die Sie zuvor definiert haben:

procedure UpdateStatusBar;

Klicken Sie in Ihrem Code mit der rechten Maustaste auf UpdateStatusBar, und wählen Sie Klasse beim Cursor vervollständigen, damit RAD Studio ein Grundgerüst für die Definition der Prozedur hinzufügt und zwar im implementation-Teil des Codes:

procedure TTextEditorForm.UpdateStatusBar;
begin

end;

Definieren Sie die Logik der Prozedur UpdateStatusBar zwischen den Schlüsselwörtern begin und end wie folgt:

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

Fügen Sie in C++ zum Definieren dieser neuen Funktion in Ihrer Anwendung die folgende Funktionssignatur dem private Abschnitt der Klasse TTextEditorForm in der Datei TextEditorUnit.h direkt unterhalb der Variable CurrentFile hinzu, die Sie zuvor definiert haben:

void UpdateStatusBar();

Wählen Sie die Implementierungsdatei TextEditorUnit.cpp aus, und implementieren Sie diese Funktion wie folgt:

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

Sie können jetzt UpdateStatusBar aus allen Ereignisbehandlungsroutinen aufrufen, um die Statusleiste zu aktualisieren.

Das erste Mal sollten Sie die in der Statusleiste angezeigten Informationen beim Start Ihrer Anwendung aktualisieren. Dafür können Sie das Ereignis OnCreate des Formulars verwenden:

  1. Klicken Sie auf die Registerkarte Design, um zurück zum Formular-Designer zu wechseln.
  2. Wählen Sie in der Strukturansicht die Formular-Komponente mit dem Namen TextEditorForm aus.
  3. Klicken Sie im Objektinspektor auf die Registerkarte Ereignisse.
  4. Doppelklicken Sie auf der Registerkarte Ereignisse auf das Wertefeld des OnCreate-Ereignisses. RAD Studio wechselt zum Quelltext-Editor und fügt ein Grundgerüst für die Definition der neuen Ereignisbehandlungsroutine hinzu. Rufen Sie mit dieser Ereignisbehandlungsroutine Ihre UpdateStatusBar-Prozedur auf:
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();
}

Beachten Sie, dass vor dem Aufruf von UpdateStatusBar eine leere Zeile in der TMemo-Komponente eingefügt wird. Dadurch wird der Zeilenzähler des Memofeldes initialisiert, damit der Zeilenzähler in der Statusleiste am Anfang "1" Zeile anstatt "0" Zeilen anzeigt.

Wiederholen Sie die obigen Schritte für die Ereignisse OnKeyUp und OnMouseUp der TMemo-Komponente Editor:

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();
}

Erstellen von Ereignisbehandlungsroutinen für die Einträge im Menü "File"

Wiederholen Sie die obigen Schritte für die Ereignisse OnKeyUp und OnMouseUp der TMemo-Komponente (Editor):

Auswählen von Neue Aktion

Wählen Sie dann im Objektinspektor die Registerkarte Ereignisse aus, und doppelklicken Sie auf das Eingabefeld neben dem Ereignis OnExecute. Der Quelltext-Editor wird geöffnet, und ein Grundgerüst für die neue Ereignisbehandlungsroutine wird angezeigt. Schreiben Sie in diese Ereignisbehandlungsroutine den Code, der ausgeführt werden soll, wenn der Benutzer Datei > Neu auswählt.

Delphi:
Hinweis: Fügen Sie der uses-Klausel im implementation-Abschnitt die Unit FMX.DialogService.Sync hinzu, entsprechend dem folgenden Codefragment:
implementation

{$R *.fmx}

uses
 FMX.DialogService.Sync;
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++:
Hinweis: Fügen Sie der include-Liste den Header FMX.DialogService.Sync.hpp hinzu, entsprechend dem folgenden Codefragment:
//---------------------------------------------------------------------------

#include <fmx.h>
#pragma hdrstop

#include "TextEditorForm.h"
#include <FMX.DialogService.Sync.hpp>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
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.
        }
    }
}
C++:
Delphi:
// File > Open
procedure TTextEditorForm.OpenActionExecute(Sender: TObject);
var
  FileName: String;
begin
  if OpenFileDialog.Execute = 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 = 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)) {
            TModalResult UserResponse = TDialogServiceSync::MessageDialog(
                L"File already exists. Do you want to overwrite?",
                TMsgDlgType::mtInformation, mbYesNo, TMsgDlgBtn::mbYes, 0);
            if (UserResponse == mrNo) {
                return;
            }
        }
        TextEditorForm->Editor->Lines->SaveToFile(FileName);
        CurrentFile = FileName;
        Caption = L"Text Editor - " + ExtractFileName(FileName);
    }
}

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

Erstellen von Ereignisbehandlungsroutinen für die Einträge im Menü "Edit" und "Format"

Gehen Sie für die Implementierung der Aktionen für die Einträge in den Menüs "Edit" und "Format" genauso vor wie bei den Aktionen für das Menü "File" vor. Diese Ereignisbehandlungsroutinen sind ziemlich einfach: sie leiten die Aktion nur an das Memofeld weiter, weil die gesamte benötigte Funktionalität bereits in der Klasse TMemo implementiert ist, und sie rufen UpdateStatusBar auf, falls die Aktion Auswirkungen auf die Position des Textcursors oder den Zeilenzähler hat.
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;
Hinweis: Fügen Sie der uses-Klausel im implementation-Abschnitt die Unit FMX.DialogService.Sync hinzu, entsprechend dem folgenden Codefragment:
implementation
 
{$R *.fmx}
 
uses
  FMX.DialogService.Sync, FMX.Memo.Types;
// 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();
}
Hinweis: Fügen Sie der include-Liste den Header FMX.DialogService.Sync.hpp hinzu, entsprechend dem folgenden Codefragment:
//---------------------------------------------------------------------------
 
#include <fmx.h>
#pragma hdrstop
 
#include "TextEditorForm.h"
#include <FMX.DialogService.Sync.hpp>
#include <FMX.Memo.Types.hpp>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
// Edit > Delete
void __fastcall TTextEditorForm::DeleteActionExecute(TObject *Sender)
{
    if (TextEditorForm->Editor->SelLength > 0) {
        TextEditorForm->Editor->DeleteSelection();
    } else {
        TextEditorForm->Editor->DeleteFrom(TextEditorForm->Editor->CaretPosition, 1, TDeleteOptions() << 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();
}

Weiter

Compilieren und Ausführen der Anwendung