- Стандартные диалоговые объекты
- Диалоговое окно для ввода текста
- Функция MsgBox в системе Visual Basic
- Вывод сообщений в системах BCB и Delphi
- Универсальные и специализированные диалоги
- Выбор файла в режиме диалога
- Выбор файла для сохранения данных
- Диалог по поводу выбора шрифта
- Диалог по выбору цвета
- Диалоги по установкам и настройкам принтера
- Диалоговые окна для поиска и замены текста
- Выбор графических файлов
Диалоговые окна для поиска и замены текста
Опубликовано admin в Сб, 02/20/2010 - 00:42
Приложение 6_15 (VB).
Объектами для поиска (FindDialog), поиска и замены (ReplaceDialog) располагают только системы BCB и Delphi. Функции их узко специализированы, и работают эти объекты только с текстами, находящимися на поле компонент RichEdit. Приведенный ниже текст приложения представляет собой слегка переработанный пример из help-файла системы BCB. Для его функционирования на форме должны быть расположены объекты RichEdit1, Button1 и FindDialog1. В составе приложения содержится всего два обработчика событий OnClick для кнопки и OnFind для диалога поиска.
После запуска приложения на поле редактора RichEdit1 надо набрать какой-нибудь текст и переместить курсор в начало текста. Затем нужно щелкнуть по кнопке с надписью <Начать поиск> для инициализации диалогового окна FindDialog1. На поле ввода открывшегося окна набирается поисковый фрагмент, который может содержать более одного слова. Запуск процедуры поиска начинается после щелчка по кнопке <Найти далее>, в результате которого возникает событие OnFind, и управление передается второму обработчику.
Содержимое поля редактора используется как одна длинная строка (RichEdit1->Text), в которой поиск начинается либо с самого первого символа (from=0), либо с позиции, следующей за ранее найденным выделенным фрагментом, если таковой существует. Переменная len хранит количество символов, оставшихся до конца длинной строки, и вместе с начальной позицией from определяет область поиска.
При нажатии кнопки <Найти далее> поисковый образ из окна ввода переносится в свойство FindDialog1->FindText. Собственно поиск осуществляет метод FindText, принадлежащий классу TRichEdit. Первый аргумент этого метода представляет поисковый образ, второй и третий аргументы задают область поиска. Четвертый аргумент представляет собой множество, элементы которого уточняют специфику поиска. Единственный член этого множества, использованный в нашем примере (stMatchCase), предписывает при сравнении текстов игнорировать разницу между большими и малыми буквами. К сожалению, эта возможность не распространяется на русскоязычные тексты. Если поисковый образ обнаружен в заданной зоне, то метод возвращает номер первой позиции найденного фрагмента. В противном случае возвращается -1. Обратите внимание на передачу фокуса RichEdit1->SetFocus(). Пока мы набирали искомое слово и щелкали по кнопке, в центре внимания операционной системы находилось диалоговое окно FindDialog. Но для того, чтобы подсветить найденный текст, надо не только установить новые значения свойств SelStart и SelLength, но и активизировать объект RichEdit1. На рис. 6.20 приведен момент работы приложения.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
FindDialog1->Execute();
}
//------------------------------------------------------------------
void __fastcall TForm1::FindDialog1Find(TObject *Sender)
{
int from=0, len, pos;
if(RichEdit1->SelLength != 0)
from = RichEdit1->SelStart + RichEdit1->SelLength;
len = RichEdit1->Text.Length() - from;
pos = RichEdit1->FindText(FindDialog1->FindText,from,len,
TSearchTypes()<< stMatchCase);
if(pos!=-1)
{ RichEdit1->SetFocus();
RichEdit1->SelStart=pos;
RichEdit1->SelLength=FindDialog1->FindText.Length();
}
}

Рис. 6.20. Объект FindDialog в работе
Диалоговое окно ReplaceDialog построено как расширенный вариант окна FindDialog. Однако с его помощью можно вести поиск и замену не только в полнофункциональных редакторах текста RichEdit, но и в более простых компонентах типа Memo. Ниже приводится и комментируется пример такого диалога, заимствованный из help-файла. На форме расположены компоненты Memo1, кнопка Button1 (инициатор появления окна диалога) и ReplaceDialog1. Диалоговое окно возникает на экране в результате обращения к методу Execute. Вообще говоря, обработчик события OnClick можно бы несколько расширить за счет указания позиции диалогового окна на экране. Например, разместив его под окном Memo1:
ReplaceDialog1->Pos=Point(Left+5,Top+40+Memo1->Heght);
Но не так уж и трудно вручную перетащить появившееся окно в более удобное место.
Обработчик события OnReplace получит управление после щелчка по одной из кнопок <Заменить> (Replace) или <Заменить все> (Replace All). Правда, до этого нужно разместить в поле Memo1 какой-либо текст и набрать в полях диалогового окна искомый и заменяющий его фрагмент (рис. 6.22). Обратите внимание на способ приведения типа объекта Sender, пославшего сообщение OnReplace и имеющего тип TObject*, к типу указателя dlg, выполненное по классическому стандарту языка Си.
Приложение 6_16 (BCB).
Для поиска фрагмента, подлежащего замене, используется метод Pos, примененный к содержимому Memo1 (Memo1->Lines->Text). Если искомый фрагмент обнаружен, то производится выделение найденного текста (Memo1->SelText) путем формирования начального индекса в строке (SelStart) и длины выделенного текста (SelLength), совпадающей с длиной поискового образа. После этого выделенный фрагмент заменяется на заданное значение ReplaceText. Если поисковый образ не обнаружен (функция Pos возвратила нулевое значение), выдается короткий звуковой сигнал.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ReplaceDialog1->Execute();
}
//-------------------------------------------------------------------
void __fastcall TForm1::ReplaceDialog1Replace(TObject *Sender)
{
TReplaceDialog *dlg = (TReplaceDialog *)Sender;
int pos = Memo1->Lines->Text.Pos(dlg->FindText);
if (pos > 0)
{
Memo1->SelStart = pos - 1;
Memo1->SelLength = dlg->FindText.Length();
Memo1->SelText = dlg->ReplaceText;
}
else
MessageBeep(0);
}
Для управления деталями поиска и замены можно использовать как кнопки и пометки в диалоговом окне, так и значения подсвойств комплексного свойства Option. Среди них параметры, задающие направление поиска (frDown), поиск отдельного слова (frWholeWord) или произвольного вхождения (frDisableWholeWord), указание об игнорировании или учете разницы между большими и малыми буквами (frMatchCase, frDisable MatchCase), необходимость одноразовой (frReplace) или многократной (frReplaceAll) замены и др. Каждое из таких свойств принимает одно из двух логических значений, устанавливая одновременно правильное значение противоположного по смыслу свойства.
На рис. 6.21 и 6.22 представлены кадры работы приложения до и после замены фрагмента «bbb ccc» на тройку символов «666».

Рис. 6.21. Диалоговое окно перед началом замены

Рис.6.22. Редактируемый текст после однократной замены
Приложение 6_17 (BCB).
Функция Pos может быть с успехом использована не только в обработчике события OnReplace, но и в обработчике события OnFind. И это дает возможность производить поиск не только в продвинутых редакторах типа RichEdit, но и в более простых объектах типа Memo. Однако здесь потребуется небольшая хитрость. Дело в том, что при поиске и замене найденный фрагмент заменяется указанным текстом и при продолжении замен поиск в строке Memo->Lines->Text можно начинать с начала строки. При просто поиске потребуется пропускать ранее найденные вхождения. Поэтому надо контролировать позицию предыдущего вхождения, и продолжать поиск вслед за очередным выделенным фрагментом. В этом нам поможет глобальная переменная len, предназначенная для хранения длины уже обработанной части строки, и локальная переменная q, в которую каждый раз переносится необработанный хвост. Ниже приводится текст приложения, которое может искать вхождения как в объектах RichEdit, так и в записных книжках типа Memo. Для его работы существенно то, что при инициализации поиска в глобальную переменную len заносится 0.
int len; //глобальная переменная
void __fastcall TForm1::Button1Click(TObject *Sender)
{
len=0;
FindDialog1->Execute();
}
//-------------------------------------------------------------------
void __fastcall TForm1::FindDialog1Find(TObject *Sender)
{
AnsiString q=RichEdit1->Lines->Text.Delete(1,len);
TFindDialog *dlg = (TFindDialog *)Sender;
int pos = q.Pos(dlg->FindText);
if (pos > 0)
{
RichEdit1->SelStart = len+pos-1;
len=RichEdit1->SelStart+dlg->FindText.Length();
RichEdit1->SelLength = dlg->FindText.Length();
RichEdit1->SetFocus();
}
else MessageBeep(0);
}
Приложение 6_18 (Delphi).
Аналогичный вариант для Delphi выглядит следующим образом:
var
Form1: TForm1;
len : integer; {глобальная переменная}
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
len:=0;
FindDialog1.Execute;
end;
procedure TForm1.FindDialog1Find(Sender: TObject);
var
j,p:integer;
q1,q:String;
begin
p:=length(Memo1.Lines.Text);
q1:=FindDialog1.FindText;
{перенос хвоста строки в q}
for j:=len+1 to p do
q:=q+Memo1.Lines.Text[j];
{поиск вхождения q1 в q}
p:=Pos(q1,q);
if p>0 then begin
Memo1.SelStart:=len+p-1;
len:=Memo1.SelStart+Length(FindDialog1.FindText);
Memo1.SelLength:=Length(FindDialog1.FindText);
Memo1.SetFocus; end
else MessageBeep(0);
end;
end.
От переменной с именем pos здесь пришлось отказаться, т.к. Object Pascal в отличие от C++ не делает разницы между большими и малыми буквами, и имя переменной начинало конфликтовать с функцией Pos. Вместо нее использована переменная p. Во-вторых, вместо удаления обработанного начала длинной строки (функция Delete в предыдущем примере) пришлось переносить необработанный хвост посимвольно. В системе Delphi функция Delete предназначена для другой цели — она удаляет строку с указанным номером из Memo.
