Шаг 58 - Компонент TRichEdit вместе с TFindDialog и TReplaceDialog

Я не сомневаюсь, что читатель уже довольно хорошо разбирается в VCL, чтобы самостоятельно освоить общие принципы применения TRichEdit. Как мне кажется, использование свойств SelStart, SelLength, SelText для выделения и изменения текста достаточно интуитивно, также как и изменение атрибутов этого текста с помощью свойства SelAttributes. На мой взгляд, достаточно интересным примером использования послужило бы описание стандартных функций поиска и замены, благо в TRichEdit есть соответствующий метод FindText. Форму делаем, например такую:

gif/58_1.gif (3878 b)

Впрочем, подпись формы можно и полаконичнее :)). В RichEdit я кое-что впечатал, видимо, фантазии не хватает :( но для пробного поиска и замена как раз сойдет. Главное меню никаких субпунктов не содержит, поэтому и обработчики такие. Листинг:

#include <stdio.h>//чтоб sprintf работал
//---------------------------------------------------------------------------

void __fastcall TForm2::Find1Click(TObject *Sender)
{
Find->FindText = RichEdit1->SelText;
Find->Execute();        
}
//---------------------------------------------------------------------------

void __fastcall TForm2::Replace1Click(TObject *Sender)
{
Replace->FindText = RichEdit1->SelText;
Replace->Execute();        
}
//---------------------------------------------------------------------------
void __fastcall TForm2::FindFind(TObject *Sender)
{
if((Sender!=Find)&&(Sender!=Replace))return;
TFindDialog* f = (TFindDialog*)Sender;
//комментарий. Дело в том, что TReplaceDialog
//является потомком TFindDialog, поэтому это преобразование сработает в любом случае
//будь это TFindDialog или TReplaceDialog
TSearchTypes st;
//Опции, введенные пользователем
if(f->Options.Contains(frMatchCase))st<<stMatchCase;
if(f->Options.Contains(frWholeWord))st<<stWholeWord;
if(RichEdit1->SelLength)RichEdit1->SelStart++;
//Когда программа находит что-то, она подсвечивает текст.
//Если HideSelection==true и фокус лежит не на основной форме,
//то выделение видно не будет
RichEdit1->HideSelection = false;
int Found = RichEdit1->FindText(f->FindText,RichEdit1->SelStart,
                                RichEdit1->Text.Length(),st);
if(Found!=-1)
        {
        RichEdit1->SelStart = Found;
        //Прокрутить окно ввода до выделенного места. 
        //С таким же успехом здесь мог быть метод Perform.
        SendMessage(RichEdit1->Handle,EM_SCROLLCARET,0,0);
        RichEdit1->SelLength = f->FindText.Length();
        }
else    {
        Application->MessageBox("Searching has reached the end of the document",
        "Search",MB_OK);
        f->CloseDialog();
        };
//SetFocus(); //эта инструкция пригодилась бы, 
	               //если бы не был установлен флаг HideSelection
}
//---------------------------------------------------------------------------
void __fastcall TForm2::ReplaceReplace(TObject *Sender)
{
FindFind(Sender);
if(RichEdit1->SelLength==0)return;
char buf[64];
sprintf(buf,"Replace this occurence of \"%s\"?",Replace->FindText.c_str());
if(Application->MessageBox(buf,"Replace",MB_YESNO)==IDYES)
        RichEdit1->SelText = Replace->ReplaceText;
if(Replace->Options.Contains(frReplaceAll))
ReplaceReplace(Sender);
//Здесь рекурсивное обращение к функции. 
//Возможно не самый лучший вариант, поскольку
//при появлении ошибки в алгоритме вылетит исключение
//Stack overflow, но зато самый краткий.
}
//---------------------------------------------------------------------------

Можно использовать при создании очередного текстового редактора. Логика в общем-то всегда одинаковая, с небольшими отличиями. Правда, не предусмотрено направление поиска, но это всегда можно реализовать. Проект можно загрузить.


Загрузить проект | Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Аванесов Самвел - 13.03.2002