7. Textový editor II
  1. Následující aplikace nás seznámí s používáním dialogových oken hledání a nahrazování textu. Začneme vývojem nové aplikace. Na formulář umístíme komponentu RichEdit a zapíšeme do ní nějaký text. Na tomto textu budeme demonstrovat funkce hledání a nahrazování textu. Vlastnost HideSelection této komponenty nastavíme na false. Na formulář dále vložíme komponenty FindDialog a ReplaceDialog. Vlastnost Options obou komponent nastavíme na [frDown, frHideUpDown]. Formulář ještě vybavíme nabídkou s volbami Edit | Find a Edit | Replace. Obsluha volby Edit | Find je tvořena příkazy:

  2. FindDialog1->FindText = RichEdit1->SelText;
    FindDialog1->Execute();
    a obsluha volby Edit | Replace:
    ReplaceDialog1->FindText = RichEdit1->SelText;
    ReplaceDialog1->Execute();
    Pro komponentu FindDialog vytvoříme ještě obsluhu události OnFind (nazveme ji Find). Tato obsluha bude tvořena příkazy:
    TSearchTypes st;
    TFindDialog *cd;
    int newpos;
    if ((cd = dynamic_cast<TFindDialog *> (Sender)) == 0)
      MessageBox(NULL, "Dynamic Cast Failed!", "Find/Rep", MB_OK);
    if (cd->Options.Contains(frMatchCase))
      st << stMatchCase;
    if (cd->Options.Contains(frWholeWord))
      st << stWholeWord;
    if (RichEdit1->SelLength)
      RichEdit1->SelStart += 1;
    newpos = RichEdit1->FindText(cd->FindText, RichEdit1->SelStart,
      RichEdit1->Text.Length(), st);
    if (newpos != -1) {
      RichEdit1->SelStart = newpos;
      RichEdit1->SelLength = cd->FindText.Length();
    }
    else {
      MessageBox(NULL, "End of document reached.", "Find/Rep", MB_OK);
      RichEdit1->SelStart = 0;
    }
    Prostudujte si tuto obsluhu. Zpracovávají se zde volby dialogového okna hledání. Stejnou obsluhu je nutno ještě připojit ke stejné události komponenty ReplaceDialog. U komponenty ReplaceDialog je nutno vytvořit ještě obsluhu události OnReplace (nazveme ji Replace). Bude tvořena příkazy:
    if (RichEdit1->SelLength == 0)
      Find(Sender);
    else {
      RichEdit1->SelText =  ReplaceDialog1->ReplaceText;
      Find(Sender);
    }
    if (ReplaceDialog1->Options.Contains(frReplaceAll))
      while (RichEdit1->SelLength !=0)
        Replace(Sender);
    Zbývá ještě vytvořit obsluhu události OnCreate formuláře. Je tvořena příkazem
    RichEdit1->SelStart = 0;
    Aplikace je hotova, můžeme ji vyzkoušet. Pokuste se přidat tyto funkce do aplikace textového editoru vytvořeného v předchozí kapitole.
  3. V další aplikaci se více seznámíme s komponentou RichEdit. Tato aplikace je dlouhá, nebudeme ji vytvářet, ale stáhneme si ji. Jedná se o demonstrační aplikaci firmy Borland. Aplikaci vyzkoušejte. Aplikace obsahuje paletu nástrojů, pravítko a stavový řádek. Podrobněji se podíváme pouze na některé obsluhy událostí.

  4. Aplikace obsahuje další formulář s informacemi o aplikaci. Tento formulář obsahuje pouze obsluhu události OnShow. Obsluha bude tvořena následujícími příkazy (zjistíme zde velikost dostupné paměti a procento jejího využití):
    TMemoryStatus MS;
    MS.dwLength = sizeof(MS);
    GlobalMemoryStatus(&MS);
    PhysMem->Caption = FormatFloat((AnsiString)"#,###' KB'",
      MS.dwTotalPhys / 1024);
    LPSTR lpMemLoad = new char[5];
    sprintf(lpMemLoad,"%d %%",MS.dwMemoryLoad);
    FreeRes->Caption = (AnsiString)lpMemLoad;
    delete [] lpMemLoad;
    Tento formulář je vyřazen ze seznamu automaticky vytvářených formulářů.
  5. Začneme nejprve popisovat jednoduché obsluhy událostí. Obsluha volby Edit | Cut je tvořena příkazem:

  6. RichEdit1->CutToClipboard();
    Stejná obsluha je přiřazena i stisku tlačítka CutButton. Obdobně jsou vyřešeny i volby Edit | Copy a Edit | Paste (a odpovídající tlačítka). Obsluha volby Edit | Font (tlačítko pro tuto funkci nemáme) je tvořena příkazy:
    FontDialog1->Font->Assign( RichEdit1->SelAttributes );
    if ( FontDialog1->Execute() )
      CurrText()->Assign( FontDialog1->Font );
    RichEdit1->SetFocus();
    Volba Help | About je tvořena příkazy (je potřeba vložit hlavičkový soubor druhého formuláře do jednotky prvního formuláře):
    Form2 = new TForm2(Application);
    Form2->ShowModal();
    delete Form2;
    Pro další obsluhy voleb v nabídce jsou vytvořeny další položky a metody formuláře. Do soukromé části deklarace formuláře jsou vloženy deklarace:
    AnsiString FFileName;
    bool FUpdating;
    int FDragOfs;
    bool FDragging;
    TTextAttributes *__fastcall CurrText(void);
    void __fastcall GetFontNames(void);
    void __fastcall SetFileName(const AnsiString FileName);
    void __fastcall CheckFileSave(void);
    void __fastcall SetupRuler(void);
    void __fastcall SetEditRect(void);
    void __fastcall ShowHint(TObject *Sender);
    Na začátku programové jednotky hlavního formuláře je deklarace následujících konstant:
    const float RulerAdj = 4.0/3.0;
    const int GutterWid = 6;
    Implementace uvedených metod bude vypadat takto (je zde i další pomocná funkce):
    TTextAttributes *__fastcall TMainForm::CurrText(void)
    {
      return RichEdit1->SelAttributes;
    }
    int __stdcall EnumFontsProc(TLogFontA &LogFont,
      TTextMetricA &/*TextMetric*/, int /*FontType*/, Pointer Data)
    {
      TCharsetObject *FontCharset;
      FontCharset = new TCharsetObject((int)LogFont.lfCharSet);
      ((TStrings *)Data)->AddObject((AnsiString)LogFont.lfFaceName,
        FontCharset);
      return 1;
    }
    void __fastcall TMainForm::GetFontNames(void)
    { HDC hDC = GetDC(0);
      void * cTmp = (void *)FontName->Items;
      EnumFonts(hDC, NULL, (FONTENUMPROC) EnumFontsProc, (long) cTmp );
      ReleaseDC(0,hDC);
      FontName->Sorted = True;
    }
    void __fastcall TMainForm::SetFileName(const AnsiString FileName)
    {
      LPSTR lpBuf = new char[MAX_PATH];
      sprintf(lpBuf, LoadStr(Percent_s_102).c_str(),
        ExtractFileName(FileName).c_str(), Application->Title.c_str());
      Caption = (AnsiString)lpBuf;
      FFileName = FileName;
      delete lpBuf;
    }
    void __fastcall TMainForm::CheckFileSave(void)
    { if ( RichEdit1->Modified ) {
        switch(MessageBox(Handle,LoadStr(SaveChanges_103).c_str(),
        LoadStr(Confirmation_104).c_str(),
        MB_YESNOCANCEL | MB_ICONQUESTION))
            {  case ID_YES    : FileSaveClick(this);
               case ID_CANCEL : Abort();
            };
       }
    }
    void __fastcall TMainForm::SetupRuler(void)
    { int iCtr = 1;
      char sTmp[201];
      while (iCtr < 200) {
        sTmp[iCtr] = 9;
        iCtr++;
        sTmp[iCtr] = '|';
        iCtr++;
      }
      Ruler->Caption = (AnsiString)sTmp;
    }
    void __fastcall TMainForm::SetEditRect(void)
    { TRect Rct = Rect(GutterWid, 0, RichEdit1->ClientWidth-GutterWid,
                  ClientHeight);
      SendMessage(RichEdit1->Handle, EM_SETRECT, 0, long(&Rct));
    }
    Pokuste se určit, co provádějí jednotlivé metody. Povšimněte si že v těchto metodách používáme zdroje řetězců. Má to ten důvod, že aplikaci se později budeme snažit převést z angličtiny na němčinu a švédštinu. V metodách se používají také další objekty. Jedná se o instance třídy TCharsetObject. Tato třída reprezentuje znakovou množinu písma. Třída má deklaraci:
    class TCharsetObject : public TObject
    {
    public:
        int Charset;
        __fastcall TCharsetObject(int FCharset);
    };
    a definice konstruktoru této třídy vypadá takto:
    __fastcall TCharsetObject::TCharsetObject(int FCharset)
      : TObject()
    {
         Charset = FCharset;
    }
    Jelikož instance těchto objektů budeme přiřazovat do vlastnosti Objects seznamů řetězců jmen písem, musíme také zajistit jejich uvolnění při ukončení aplikace. Vytvoříme tedy obsluhu události OnDestroy formuláře. Bude tvořena příkazy:
    for(int n = 0;n < FontName->Items->Count;n++)
      if( FontName->Items->Objects[n] ){
        delete FontName->Items->Objects[n];
        FontName->Items->Objects[n] = NULL;
      }
    Nyní se již můžeme podívat na obsluhy dalších voleb v nabídce. Obsluha volby File | New bude tvořena příkazy:
    CheckFileSave();
    SetFileName((AnsiString)LoadStr(Untitled_101));
    RichEdit1->Lines->Clear();
    RichEdit1->Modified = false;
    Obsluhu volby File | Open a tlačítka OpenButton tvoří:
    CheckFileSave();
    if (OpenDialog->Execute()) {
      RichEdit1->Lines->LoadFromFile(OpenDialog->FileName);
      SetFileName(OpenDialog->FileName);
      RichEdit1->SetFocus();
      RichEdit1->Modified = false;
      RichEdit1->ReadOnly = OpenDialog->Options.Contains(ofReadOnly);
    }
    Obdobně pro File | Save a tlačítko SaveButton to budou příkazy:
    if ( !strcmp(FFileName.c_str(),LoadStr(Untitled_101).c_str()) )
      FileSaveAsClick(Sender);
    else {
      RichEdit1->Lines->SaveToFile(FFileName);
      RichEdit1->Modified = false;
    }
    Obsluhu File | Save As tvoří příkazy:
    if ( SaveDialog->Execute() ) {
      RichEdit1->Lines->SaveToFile(SaveDialog->FileName);
      SetFileName(SaveDialog->FileName);
      RichEdit1->Modified = false;
    }
    Obsluhu volby File | Print a tlačítka PrintButton tvoří příkaz:
    if ( PrintDialog->Execute() ) RichEdit1->Print( FFileName );
    a obsluhu File | Exit příkaz:
    Close();
    Obsluha volby Edit | Undo a stisknutí tlačítka UndoButton je tvořena:
    if ( RichEdit1->HandleAllocated() )
      SendMessage(RichEdit1->Handle, EM_UNDO, 0, 0);
    Pokuste se pochopit jak tyto obsluhy a další metody pracují. Další obsluhy voleb nám již srozumitelné asi nebudou. Obsluhu Help | Contents tvoří příkaz:
    Application->HelpCommand(HELP_CONTENTS, 0);
    Obsluhu Help | Search for Help On nápovědy tvoří:
    Application->HelpCommand(HELP_PARTIALKEY, (long) "");
    a obsluha Help | How to Use Help je tvořena:
    Application->HelpCommand(HELP_HELPONHELP, 0);
    Tím jsme dokončili vytváření obsluh voleb v nabídce. Zbývá nám vyřešit ještě stisknutí několika tlačítek na paletě. Obsluha stisku tlačítka BoldButton obsahuje příkazy:
    if ( !FUpdating ) {
      if ( BoldButton->Down )
        CurrText()->Style = CurrText()->Style << fsBold;
      else
        CurrText()->Style = CurrText()->Style >> fsBold;
    }
    Pro tlačítko ItalicButton a UnderlineButton to jsou obdobné obsluhy. Pro všechna tři tlačítka zarovnávání bude použita obsluha s příkazy:
    if ( !FUpdating ) {
      TControl *oAliBtn = (TControl*)(Sender);
      RichEdit1->Paragraph->Alignment = (TAlignment)oAliBtn->Tag;
    }
    Obsluha stisku posledního tlačítka, tj. tlačítka BulletsButton je tvořena příkazy:
    if ( !FUpdating )
      RichEdit1->Paragraph->Numbering = (TNumberingStyle)BulletsButton->Down;
    Zbývají ještě obsluhy OnChange editačního ovladače velikosti písma a kombinovaného ovladače jména písma. Obsluha editačního ovladače je tvořena příkazy:
    int fontsize = atoi(FontSize->Text.c_str());
    if ((!FUpdating) &&  (fontsize)) {
      if (fontsize < 1) {
        ShowMessage(LoadStr(Numberbetween_105));
        FontSize->Text = 1;
      }
      else if (fontsize > 1638) {
        ShowMessage(LoadStr(Numberbetween_105));
        FontSize->Text = 1638;
      }
      CurrText()->Size = atoi(FontSize->Text.c_str());
    }
    a obsluha kombinovaného okna obsahuje:
    TCharsetObject* ChasrsetObject;
    if ( !FUpdating ) {
      ChasrsetObject = (TCharsetObject*)FontName->Items
                       ->Objects[FontName->ItemIndex];
      CurrText()->Charset = (unsigned char)ChasrsetObject->Charset;
      CurrText()->Name = FontName->Items->Strings[FontName->ItemIndex];
    }
    Dále se budeme zabývat vytvářením obsluh dalších událostí. V události OnCreate formuláře budeme také měnit obsluhu události OnHint aplikace. Do soukromé části deklarace třídy formuláře tedy vložíme
    void __fastcall ShowHint(TObject *Sender);
    a do jednotky formuláře zapíšeme změněnou obsluhu.
    void __fastcall TMainForm::ShowHint(TObject* /*Sender*/)
    {
      StatusBar->SimpleText = Application->Hint;
    }
    Nyní již můžeme vytvořit obsluhu události OnCreate formuláře. Bude tvořena těmito příkazy:
    Application->OnHint = &ShowHint;
    OpenDialog->InitialDir = ExtractFilePath(ParamStr(0));
    SaveDialog->InitialDir = OpenDialog->InitialDir;
    GetFontNames();
    SetupRuler();
    SelectionChange(this);
    Pro komponentu RichEdit vytvoříme obsluhu události OnSelectionChange (nazveme ji SelectionChange) s těmito příkazy:
    char sizebuf[6];
    try {
      FUpdating = true;
      FirstInd->Left = int(RichEdit1->Paragraph->FirstIndent*RulerAdj)-
        4+GutterWid;
      LeftInd->Left  = int((RichEdit1->Paragraph->LeftIndent+
        RichEdit1->Paragraph->FirstIndent)*RulerAdj)-
        4+GutterWid;
      RightInd->Left = Ruler->ClientWidth-6-int(
        (RichEdit1->Paragraph->RightIndent+GutterWid)*RulerAdj);
      BoldButton->Down = RichEdit1->SelAttributes->Style.Contains(fsBold);
      ItalicButton->Down = RichEdit1->SelAttributes->Style.Contains(fsItalic);
      UnderlineButton->Down = RichEdit1->SelAttributes->Style.Contains(fsUnderline);
      BulletsButton->Down = bool(RichEdit1->Paragraph->Numbering);
      FontSize->Text = itoa(RichEdit1->SelAttributes->Size, sizebuf, 10);
      FontName->Text = RichEdit1->SelAttributes->Name;
      switch((int)RichEdit1->Paragraph->Alignment)
      { case 0: LeftAlign->Down   = true; break;
        case 1: RightAlign->Down  = true; break;
        case 2: CenterAlign->Down = frue; break;
      }
    }
    catch (...) {
      FUpdating = false;
    }
    FUpdating = false;
    Obsluha OnResize pravítka bude tvořena příkazem:
    RulerLine->Width = (int)Ruler->ClientWidth - (RulerLine->Left*2);
    a obsluhu OnResize formuláře tvoří příkazy:
    SetEditRect();
    SelectionChange(Sender);
    Pro formulář ještě vytvoříme obsluhu události OnPaint s příkazem
    SetEditRect();
    a obsluhu události OnCloseQuery tvořenou příkazy:
    try {
      CheckFileSave();
    }
    catch (...) {
      CanClose = false;
    }
    Do konstruktoru formuláře přidáme ještě příkaz:
    SetFileName((AnsiString)LoadStr(Untitled_101));
    Tím máme většinu aplikace hotovou. Zbývá dokončit ještě ovládání pravítka. To provedeme v dalším bodě. Pokuste se pochopit, co a jak provádějí jednotlivé obsluhy.
  7. V tomto bodě se budeme zabývat ovládáním indikátorů okrajů na pravítku. Pro všechny tři indikátory okrajů na pravítku vytvoříme obsluhy událostí OnDouseDown, OnMouseMove a OnMouseUp. První dvě z těchto obsluh jsou pro všechny tři indikátory společné. Obsluhu OnMouseDown tvoří příkazy:

  8. TLabel * oTmpLabel = (TLabel *)Sender;
    FDragOfs = oTmpLabel->Width / 2;
    oTmpLabel->Left = oTmpLabel->Left+X-FDragOfs;
    FDragging = True;
    a obsluhu OnMouseMove příkazy:
    if (FDragging) {
      TLabel * oTmpLabel = (TLabel *)Sender;
      oTmpLabel->Left = oTmpLabel->Left+X-FDragOfs;
    }
    Obsluhu OnMouseUp indikátoru prvního řádku tvoří příkazy:
    FDragging = false;
    RichEdit1->Paragraph->FirstIndent = int((FirstInd->Left+
                                        FDragOfs-GutterWid) / RulerAdj);
    LeftIndMouseUp(Sender, Button, Shift, X, Y);
    pro indikátor levého okraje použijeme příkazy:
    FDragging = false;
    RichEdit1->Paragraph->LeftIndent = int((LeftInd->Left+FDragOfs-GutterWid)/
                          RulerAdj)-RichEdit1->Paragraph->FirstIndent;
    SelectionChange(Sender);
    a pro indikátor pravého okraje příkazy:
    FDragging = false;
    RichEdit1->Paragraph->RightIndent =
      int((Ruler->ClientWidth-RightInd->Left+FDragOfs-2) /
      RulerAdj)-2*GutterWid;
    SelectionChange(Sender);
    Nyní je již naše aplikace hotova. Můžeme ji vyzkoušet.
  9. Naše aplikace má také nabídku, která umožňuje přepínat jazyk aplikace (angličtina, němčina a švédština). Obsluhy těchto voleb v nabídce jsou tvořeny příkazy (je zde i pomocná funkce):

  10. void SetLocaleOverrides(char* FileName, char* LocaleOverride)
    {
     HKEY Key;
     const char* LocaleOverrideKey = "Software\\Borland\\Locales";
     if (RegOpenKeyEx(HKEY_CURRENT_USER,LocaleOverrideKey, 0,
         KEY_ALL_ACCESS, &Key) == ERROR_SUCCESS) {
           if (lstrlen(LocaleOverride) == 3)
             RegSetValueEx(Key, FileName, 0, REG_SZ,
                           (const BYTE*)LocaleOverride, 4);
             RegCloseKey(Key);
          }
    }
    void __fastcall TMainForm::US1Click(TObject *Sender)
    {
      SetLocaleOverrides((Application->ExeName).c_str(), "ENU");
      LPSTR lpBuf = new char[256];
      sprintf(lpBuf, LoadStr(Restart_106).c_str(),
              LoadStr(Language_108).c_str());
      ShowMessage(operator +(lpBuf, LoadStr(Restart_107).c_str()));
    }
    void __fastcall TMainForm::German1Click(TObject *Sender)
    {
      SetLocaleOverrides((Application->ExeName).c_str(), "DEU");
      LPSTR lpBuf = new char[256];
      sprintf(lpBuf, LoadStr(Restart_106).c_str(),
              LoadStr(Language_109).c_str());
      ShowMessage(operator +(lpBuf, LoadStr(Restart_107).c_str()));
    }
    void __fastcall TMainForm::Swedish1Click(TObject *Sender)
    {
      SetLocaleOverrides((Application->ExeName).c_str(), "SVE");
      LPSTR lpBuf = new char[256];
      sprintf(lpBuf, LoadStr(Restart_106).c_str(),
              LoadStr(Language_110).c_str());
      ShowMessage(operator +(lpBuf, LoadStr(Restart_107).c_str()));
    }
    Tyto příkazy pouze načítají zdroje řetězců s příslušnými texty (z DLL) a přiřazují je k aplikaci. Nyní je zapotřebí vytvořit potřebné zdroje řetězců, vytvořit z nich DLL a tyto DLL uložit do stejného adresáře, jako je aplikace. Ukážeme si, jak vypadá projekt pro vytvoření DLL pro jeden jazyk (např. angličtinu; pro ostatní dva jazyky použijeme již hotové DLL). Stáhněte si soubor s projektem vytvoření DLL pro angličtinu. Rozbalte tento soubor a v C++ Builderu otevřete projekt Richenu.bpr. Překladem tohoto projektu se vytvoří potřebná DLL. Tento projekt obsahuje soubor zdrojů se zdroji řetězců, které potřebuje naše aplikace. Prohlédněte si, z jakých souborů se tento projekt skládá a přeložte jej. Při překladu vznikne soubor Richenu.enu. Další dvě DLL pro němčinu a švédštinu (Richdeu.deu a Richsve.sve) jste si stáhli společně s projektem pro vytvoření DLL pro angličtinu. Uložte všechny tyto tři DLL do stejného adresáře jako je předchozí aplikace. A vyzkoušejte, jak lze měnit jazyk volbou v nabídce. Nový jazyk se projeví až při dalším spuštění aplikace.

  11. Obvykle přerušíme provádění programu na bodu přerušení, abychom zjistili hodnotu jedné nebo více proměnných. Hodnoty určených proměnných lze zjistit ve Sledovacím okně. Do Sledovacího okna lze přidávat proměnné podle potřeby. Na každém řádku tohoto okna je vždy uvedeno jméno proměnné a její hodnota. Způsob zobrazení hodnoty je určen typem proměnné a zobrazovacím nastavením pro sledovaný prvek.

  12. Ladící prostředek a Editor kódu má službu usnadňující testování hodnoty proměnné. Jedná se o bublinkovou nápovědu vyhodnocovače výrazu. Tuto službu (ToolTip evaluator) zapínáme na stránce Code Insight dialogového okna Environment Options. Po zastavení provádění programu umístíme kurzor editoru na proměnnou a v bublinkové nápovědě je zobrazena hodnota této proměnné.
    Sledovací okno má vlastní místní nabídku. Jsou zde tyto volby:
     
    Volba Popis
    Edit Watch Umožňuje editaci sledovaného prvku (např. změna způsobu zobrazení).
    Add Watch Přidává nový prvek do Sledovacího okna.
    Enable Watch Povoluje sledovaný prvek.
    Disable Watch Zakazuje sledovaný prvek
    Delete Watch Ruší sledovaný prvek.
    Enable All Watches Povoluje všechny prvky Sledovacího okna.
    Disable All Watches Zakazuje všechny prvky Sledovacího okna.
    Delete All Watches Ruší všechny prvky Sledovacího okna.
    Stay on Top Přesouvá Sledovací okno nad ostatní okna v IDE.
    Break When Changed Když se proměnná ve Sledovacím okně změní, pak ladění je přerušeno. Změněná proměnná je zobrazena červeně.

    Volby Edit Watch a Add Watch zobrazují dialogové okno vlastností sledování (okno lze také zobrazit dvojitým kliknutím na sledovaném prvku). Do části Expression v horní části okna zadáváme jméno editované nebo přidávané proměnné. Jedná se o kombinované okno, které lze použít k výběru dříve použitých sledovacích prvků. Položku Repeat Count používáme při zkoumání polí. Umožňuje určit, kolik prvků pole má být vypisováno. Pokud zde nezadáme žádnou hodnotu, pak jsou vypisovány všechny prvky pole. Položka Digits je používána při zkoumání reálných hodnot. Zadáváme zde počet významných číslic, které mají být zobrazovány (provádí se zaokrouhlování). Značka Enabled určuje zda současný prvek je právě povolen. Okno obsahuje ještě řadu voličů, které slouží k nastavení způsobu zobrazení hodnoty.
    Jednotlivé prvky Sledovacího okna mohou být povolené nebo zakázané. Zakázané prvky jsou zobrazeny nevýrazně a jako svou hodnotu zobrazují <disabled>.
    Proměnnou do sledovacího okna lze přidat několika způsoby. Nejrychlejší je kliknout na jménu proměnné v Editoru kódu a v místní nabídce editoru zvolit Add Watch at Cursor. Sledovaný prvek je přímo přidán do Sledovacího okna. Ostatní způsoby přidávání proměnné, zobrazí dialogové okno Vlastností sledování.
    Při dosažení bodu přerušení, Sledovací okno zobrazuje současné hodnoty proměnných uvedených ve Sledovacím okně. Pokud Sledovací okno není otevřeno, pak jej zobrazíme volbou View | Watches.

  13. Inspektor ladění umožňuje zobrazit data objektů (jako jsou třídy nebo komponenty). Umožňuje také prohlížet jednoduché datové typy. Inspektor ladění je možno použít pouze při přerušení provádění programu. K prohlédnutí objektu klikneme na jméně objektu ve zdrojovém kódu a v místní nabídce Editoru kódu zvolíme Inspect. Okno Inspektora objektů obsahuje detaily zobrazeného objektu. Při prohlížení třídy, okno Inspektora objektů obsahuje tři stránky. Stránka Data zobrazuje všechny datové složky třídy v hierarchickém seznamu (nejprve jsou data vlastní třídy a dále data předků). K další inspekci datové složky dvojitě klikneme na sloupci hodnot datové složky. Tím otevřeme další okno Inspektora ladění pro určenou datovou složku. Stránka Methods Inspektora ladění zobrazuje metody třídy. Stránka Properties zobrazuje vlastnosti třídy. Stránky Methods a Properties jsou zobrazeny pouze při zkoumání třídy. Při zkoumání jednoduchých datových typů je zobrazena pouze stránka Data.

  14. Místní nabídka Inspektora ladění obsahuje několik voleb, které umožňují pracovat s Inspektorem ladění a jednotlivými proměnnými. Těmito volbami se zde nebudeme podrobněji zabývat. Inspektor ladění poskytuje kompletní přehled o stavu objektu.
    Často si potřebujeme prohlédnou všechny lokální proměnné právě prováděné funkce. Lze to provést jejich přidáním do Sledovacího okna. Lepší možností je volba Run | Inspect Local Variables. Při použití této volby okno Inspektora ladění zobrazí hodnoty všech lokálních proměnných současně prováděné funkce.
    S dalšími možnostmi ladícího prostředku se opět seznámíme v další kapitole.
7. Textový editor II