100 компонентов общего назначения библиотеки Delphi5

       

Диалоговое окно замены фрагмента текста


Компоненты имеют следующие основные свойства:

FindTextТекст, заданный пользователем для поиска или замены. Программно может быть установлен как начальное значение, предлагаемое пользователю ReplaceTextТолько в компоненте ReplaceDialog — текст, который должен заменять FindText PositionПозиция левого верхнего угла диалогового окна, заданная типом TPoint — записью, содержащей поля X (экранная координата по горизонтали) и Y (экранная координата по вертикали) LeftКоордината левого края диалогового окна, то же, что Position.X TopКоордината верхнего края диалогового окна, то же, что Position.Y OptionsМножество опций

Последний параметр Options — может содержать следующие свойства:

frDisableMatchCaseДелает недоступным индикатор С учетом регистра в диалоговом окне frDisableUpDownДелает недоступными в диалоговом окне кнопки Вверх и Вниз группы Направление, определяющие направление поиска frDisableWholeWordДелает недоступным индикатор Только слово целиком в диалоговом окне frDownВыбирает кнопку Вниз группы Направление при открытии диалогового окна. Если эта опция не установлена, то выбирается кнопка Вверх frFindNextЭта опция включается автоматически, когда пользователь в диалоговом окне щелкает на кнопке Найти далее, и выключается при закрытии диалога frHideMatchCaseУдаляет индикатор С учетом регистра из диалогового окна frHideWholeWordУдаляет индикатор Только слово целиком из диалогового окна frHideUpDownУдаляет кнопки Вверх и Вниз из диалогового окна frMatchCaseЭтот флаг включается и выключается, если пользователь включает и выключает опцию С учетом регистра в диалоговом окне. Можно установить эту опцию по умолчанию во время проектирования, чтобы при открытии диалога она была включена frReplaceПрименяется только для ReplaceDialog. Этот флаг устанавливается системой, чтобы показать, что текущее (и только текущее) найденное значение FindText должно быть заменено значением ReplaceText frReplaceAllПрименяется только для ReplaceDialog. Этот флаг устанавливается системой, чтобы показать, что все найденные значения FindText должны быть заменены значениями ReplaceText frShowHelpЗадает отображение кнопки Справка в диалоговом окне frWholeWordЭтот флаг включается и выключается, если пользователь включает и выключает опцию Только слово целиком в диалоговом окне. Можно установить эту опцию по умолчанию во время проектирования, чтобы при открытии диалога она была включена

Сами по себе компоненты FindDialog и ReplaceDialog не осуществляют ни поиска, ни замены. Они только обеспечивают интерфейс с пользователем. А поиск и замену надо осуществлять программно. Для этого можно пользоваться событием OnFind, происходящим, когда пользователь нажал в диалоге кнопку Найти далее, и событием OnReplace, возникающим, если пользователь нажал кнопку Заменить или Заменить все. В событии OnReplace узнать, какую именно кнопку нажал пользователь, можно но значениям флагов frReplace и frReplaceAll.

Поиск заданного фрагмента легко проводить, пользуясь функцией Object Pascal Pos, которая определена в модуле System следующим образом: function Pos(Substr: string; S: string): Byte; где S — строка, в которой ищется фрагмент текста, a Substr — искомый фрагмент. Функция возвращает позицию первого символа первого вхождения искомого фрагмента в строку. Если Substr в S не найден, возвращается 0.

Для организации поиска нам потребуется еще две функции: Сору и AnsiLowerCase. Первая из них определена как: function Copy(S: string; Index, Count: Integer): string;

Она возвращает фрагмент строки S, начинающийся с позиции Index и содержащий число символов, не превышающее Count. Функция AnsiLowerCase, определенная как function AnsiLowerCase(const S: string): string; возвращает строку символов S, переведенную в нижний регистр.

Теперь мы можем рассмотреть пример организации поиска. Пусть в вашем приложении имеется компонент Memo1 и при выборе раздела меню MFind вы хотите организовать поиск в тексте, содержащемся в Memo1. Для упрощения задачи исключим опцию поиска только целых слов и опцию поиска вверх от положения курсора.

Программа, реализующая поиск, может иметь следующий вид:

var SPos: integer; procedure TForm1.MFindClick(Sender: TObject); begin {запоминание позиции курсора} SPos := Memo1.SelStart; with FindDialog1 do begin {начальное значение текста поиска — текст, выделенный в Memo1} FindText := Memo1.SelText; {позиционирование окна диалога внизу Memo1} Position := Point(Form1.Left, Form1.Top + Memo1.Top + Memo1.Height); {удаление из диалога кнопок «Вверх», «Вниз», «Только слово целиком»} Options := Options + [frHideUpDown, frHideWholeWord]; {выполнение} Execute; end; end; procedure TForm1.FindDialog1Find(Sender: TObject); begin with FindDialog1 do begin if frMatchCase in Options {поиск с учетом регистра} then Memo1.SelStart := Pos(FindText, Copy(Memo1.Lines.Text, SPos + 1, Length(Memo1.Lines.Text))) + Spos - 1 {поиск без учета регистра} else Memo1.SelStart := Pos(AnsiLowerCase(FindText), AnsiLowerCase(Copy(Memo1.Lines.Text, SPos + 1, Length(Memo1.Lines.Text)))) + Spos - 1; if Memo1.SelStart >= Spos then begin {выделение найденного текста} Memo1.SelLength := Length(FindText); {изменение начальной позиции поиска} SPos := Memo1.SelStart + Memo1.SelLength + 1; end else if MessageDlg( 'Текст "'+FindText+'" не найден. Продолжать диалог?', mtConfirmation, mbYesNoCancel, 0) <> mrYes then CloseDialog; end; Memo1.SetFocus; end;

В программе вводится переменная SPos, сохраняющая позицию, начиная с которой надо проводить поиск.

Процедура MFindClick вызывает диалог, процедура FindDialog1Find обеспечивает поиск с учетом или без учета регистра в зависимости от флага frMatchCase. После нахождения очередного вхождения искомого текста этот текст выделяется в окне Memo1 и управление передается этому окну редактирования. Затем при нажатии пользователем в диалоговом окне кнопки Найти далее, поиск продолжается в оставшейся части текста. Если искомый текст не найден, делается запрос пользователю о продолжении диалога. Если пользователь не ответил на этот запрос положительно, то диалог закрывается методом CloseDialog.

В дополнение к приведенному тексту полезно в обработчики событий OnClick и OnKeyUp компонента Memo1 ввести операторы SPos := Memo1.SelStart;

Это позволяет пользователю во время диалога изменить положение курсора в окне Memo1. Это новое положение сохранится в переменной SPos и будет использовано при продолжении поиска.

При реализации команды Заменить приведенные выше процедуры можно оставить теми же самыми, заменив в них FindDialog1 на ReplaceDialog1. Дополнительно можно написать процедуру обработки события OnReplace компонента ReplaceDialog1: procedure TForm1.ReplaceDialog1Replace(Sender: TObject); begin if Memo1.SelText <> '' then Memo1.SelText := ReplaceDialog1.ReplaceText; if frReplaceAll in ReplaceDialog1.Options then ReplaceDialog1Find(Self); end;

Этот код производит замену выделенного текста и, если пользователь нажал кнопку Заменить все, то продолжается поиск вызовом уже имеющейся процедуры поиска ReplaceDialog1Find*. Если же пользователь нажал кнопку Заменить, то производится только одна замена и для продолжения поиска пользователь должен нажать кнопку Найти далее.

* Предлагаемый автором алгоритм принажатии на кнопку Заменить все заменяет только одно значение и находит следующее. На наш взгляд такия действия более логично было бы задать кнопке Заменить, а для Заменить все организовать цикл. Причем такой цикл проще осуществить в процедуре ReplaceDialog1Find. В приведенном ниже коде кроме того введена локальная переменная ss, так как свойству SelStart нельзя присваивать отрицательные значения.
procedure TForm1.ReplaceDialog1Find(Sender: TObject); var ss: integer; last: Boolean; st: string; begin with ReplaceDialog1 do begin if (frFindNext in Options) then {изменение начальной позиции поиска} SPos := Memo1.SelStart + Memo1.SelLength + 1; last := not (frReplaceAll in Options); repeat if frMatchCase in Options {поиск с учетом регистра} then ss := Pos(FindText, Copy(Memo1.Lines.Text, SPos + 1, Length(Memo1.Lines.Text))) + Spos - 1 {поиск без учета регистра} else ss := Pos(AnsiLowerCase(FindText), AnsiLowerCase(Copy(Memo1.Lines.Text, SPos + 1, Length(Memo1.Lines.Text)))) + Spos - 1; if ss >= Spos then begin {выделение найденного текста} Memo1.SelStart := ss; Memo1.SelLength := Length(FindText); if (frReplaceAll in Options) then begin {замена} Memo1.SelText := ReplaceDialog1.ReplaceText; {изменение начальной позиции поиска} SPos := Memo1.SelStart + Memo1.SelLength + 1; end; end else begin if (frReplaceAll in Options) or (frReplace in Options) then st := 'Замена "' + FindText + '" на "' + ReplaceText + '" закончена' else st := 'Текст "' + FindText + '" не найден'; if MessageDlg(st + '. Продолжать диалог?', mtConfirmation, mbYesNoCancel, 0) <> mrYes then CloseDialog; last:=true; end; until last; end; end; procedure TForm1.ReplaceDialog1Replace(Sender: TObject); begin if (frReplace in ReplaceDialog1.Options) and (Memo1.SelText <> '') then Memo1.SelText := ReplaceDialog1.ReplaceText; ReplaceDialog1Find(Self); end; - Примечание разработчика электронной версии.

Содержание раздела