Delphi

КОМПЬЮТЕРНЫЕ КУРСЫ "ПОИСК"

[Главная страница] [Delphi] [Контакты]

Создание текстового редактора


Первым делом мы должны построить базовый интерфейс пользователя приложения. Для этого добавьте в окно Designer Surface компоненты TMainMenu, TMemo, TActionList, TOpenDialog, TSaveDialog, TStatusBar (категория Win32) и компонент TToolbar.

н1-1

Форме дайте имя MainForm.

После этого выберите компонент TMainMenu и создайте группы меню Файл, Правка и Формат. Не создавайте пока что никаких пунктов меню, поскольку для реализации команд меню будут использоваться действия.

н1-2

Теперь выберите компонент ТМеmо и выполните следующие шаги:

  1.  Присвойте свойству Align значение alClient. чтобы компонент занял всю клиентскую область формы.
  2. Удалите текст Memo1 из свойства Lines.
  3. Присвойте свойству ScrollBars значение ssVertical. чтобы отобразить вертикальную линейку прокрутки и позволить пользователю без труда просматривать обширные текстовые файлы.

Меню File

Меню Файл должно содержать команды, которые позволят пользователю завершать работу приложения, создавать, загружать и сохранять файлы.

y1-3

Пока мы не будем заниматься реализацией команд Параметры страницы и Печать.

Чтобы создать команды меню Файл, и дважды щелкните на TActionList, чтобы отобразить окно редактора Action List (Список действий).

Во-первых, нам необходимо создать команду Файл - Выход. Щелкните на кнопке New Action (Новое действие), чтобы создать новое действие, и выполните следующие шаги:

  1.  Присвойте свойству Caption нового действия значение Выход.
  2. Сведите в свойстве Hint строку Выход из программы.
  3. Присвойте действию имя ExitAction.
  4. И, наконец, назначьте действие неименованному пункту меню в меню Файл.

Чтобы закрыть приложение, достаточно вызвать метод Close формы в обработчике события OnExecute действия:

procedure TMainForm.ExitActionExecute(Sender: TObject); 
begin
  Close; 
end;

Загрузка документов

Теперь необходимо реализовать команду Файл - Открыть, чтобы пользователь мог открывать существующие файлы. Во-первых, необходимо объявить приватную переменную, которая будет хранить имя файла открытого документа.

Эта переменная необходима в команде Файл - Сохранить, а также в некоторых других местах, о чем будет сказано чуть позже.

   private
    { Private declarations }
    FOpenedFile: string;
  public
    { Public declarations }
  end;

Чтобы пользователь мог выбрать существующий документ, вы должны использовать компонент TOpenDialog. Измените свойство Filter, чтобы диалоговое окно показывало только файлы с простым текстом, имеющие расширение .txt.

y1-4

Будет разумным всегда добавлять фильтр All File Types, поскольку пользователь может иметь документы с простым текстом, сохраненные с расширением, отличным от .txt.
Теперь добавьте новое действие в список действий и измените его настройки следующим образом:

  1. В свойстве Caption нового действия введите Открыть.
  2.  В свойстве Hint введите Открыть существующий документ.
  3.  Присвойте действию имя OpenAction.
  4. Назначьте свойству Shortcut комбинацию Ctrl+O.

Чтобы загрузить текстовый документ в компонент ТМеmо. вы должны сделать несколько вещей. Во-первых, вы должны вызвать метод Execute компонента TOpenDialog, чтобы пользователь мог выбрать документ. Если пользователь щелкнул на кнопке ОК в диалоговом окне, имя выбранного файла будет записано в свойство FileName компонента TOpenDialog, и метод Execute вернет значение True.

Когда метод Execute возвращает True, вы должны скопировать имя выбранного файла в переменную FOpenedFile. а затем вызвать метод LoadFromFile, чтобы загрузить выбранный текстовый документ в свойство Lines компонента ТМеmо. Опять-таки поместите этот код в обработчик события OnExecute действия.

procedure TMainForm.OpenActionExecute(Sender: TObject);
begin
  if CloseCurrentDocument and OpenDialog1.Execute then
  begin
    // Сохранение имени выбранного файла
    FOpenedFile := OpenDialog1.FileName;
    // Загрузка выбранного документа
    Memo1.Lines.LoadFromFile(FOpenedFile);
  end;
end;

И последнее что потребуется сделать – это создать команду Открыть в меню Файл и назначить действие OpenAction свойству Action нового меню.

Сохранение документов

Большинство приложений имеют две разные команды, которые позволяют пользователю сохранить документ: Сохранить и Сохранить как. Команда Сохранить используется для сохранения изменений в существующем документе, а команда Сохранить как — для сохранения документа, который не существует на диске или для сохранения копии существующего документа под другим именем.

Для начала мы реализуем команду Файл - Сохранить как. Команда Сохранить как должна позволить выбрать каталог и имя файла для документа с помощью компонента TSaveDialog. Измените свойства TSaveDialog:

  1.  В поле свойства DefaultExt введите txt, чтобы в диалоговом окне к имени файла автоматически добавлялось расширение .txt.
  2. Создайте такой же фильтр, как и для компонента TOpenDialog.
  3. Раскройте группу Options и присвойте свойству ofOverwritePrompt значение True.

После того как вы включите свойство ofOverwritePrompt в набор Options, компонент TSaveDialog автоматически сгенерирует предупреждающее сообщение, если пользователь попытается использовать имя файла, который уже используется.

Теперь откройте редактор Action List и создайте действие Сохранить как:

  1.  В поле свойства Caption введите Сохранить как...
  2. Присвойте действию имя SaveAsAction.
  3. В поле свойства Hint введите Сохранить активный документ под новым именем.

Наконец, поместите код в обработчик событий OnExecute, a затем назначьте это действие неименованному пункту в меню Файл.

procedure TMainForm.SaveAsActionExecute(Sender: TObject);
begin
  if SaveDialog1.Execute then
  begin
    // Запоминанание имени нового файла
    FOpenedFile := SaveDialog1.FileName;
    // Сохранение документа
    Memo1.Lines.SaveToFile(FOpenedFile);
    Memo1.Modified := False;
  end;
end;

Действие Сохранить должно выполнить две вещи: сохранить изменения, произведенные в активном документе, если документ существует, или отобразить диалоговое окно Сохранить как, если документ не существует.

Чтобы создать действие Сохранить, выполните следующие шаги:

  1. Создайте новое действие в редакторе Action List.
  2. В поле свойства Caption нового действия введите Сохранить.
  3. В поле свойства Hint введите Сохранить активный документ.
  4. Присвойте действию имя SaveAction.
  5. Назначьте свойству Shortcut комбинацию Ctrl+S.

Ниже показан обработчик события OnExecute действия Сохранить:

procedure TMainForm.SaveActionExecute(Sender: TObject);
begin
  // Если активный документ существует, сохраните изменения
  if FOpenedFile <> '' then
  begin
    Memo1.Lines.SaveToFile(FOpenedFile);
    Memo1.Modified := False;
  end else
    // Если документ не существует, выводится диалоговое окно Save As
    SaveAsAction.Execute;
end;

Назначьте действие SaveAction неименованному пункту в меню Файл.

Создание новых документов

Команда Файл - Новый сама по себе очень простая, поскольку мы должны выполнить всего лишь следующие шаги:

  •  Очистить переменную FOpenedFile, чтобы приложение знало, что активный документ не существует.
  • Удалить существующий текст из компонента Memo1, вызвав метод Clear.

Чтобы создать действие Новый, выполните перечисленные ниже шаги:

  1.  Создайте новое действие в редакторе Action List.
  2. В поле свойства Caption введите Новый.
  3. В поле свойства Hint введите Создать новый документ.
  4. Присвойте действию имя NewAction.
  5. Назначьте свойству ShortCut комбинацию Ctrl+N.
  6. Добавьте код в обработчик события OnExecute.
procedure TMainForm.NewActionExecute(Sender: TObject);
begin
  if CloseCurrentDocument then
  begin
    Memo1.Lines.Clear;
    FOpenedFile := '';
  end;
end;

Назначьте действие NewAction неименованному пункту в меню Файл.

Защита данных пользователя

Теперь, когда работа над меню File завершена, необходимо написать еще несколько строк кода, который будет защищать содержимое активного документа.

n1-5

Грамотно спроектированное приложение должно проверять, изменял ли пользователь содержимое активного документа, и спрашивать пользователя о том, желает ли он сохранить документ, прежде чем разрешать пользователю:

  • Создавать новый документ.
  • Открывать существующий документ.
  • Закрывать все приложение.

Например, если в редакторе Блокнот вы введете некоторый текст, а затем попытаетесь закрыть редактор, то он автоматически уведомит о том, что вы не сохранили самый последний вариант изменений в документе, и позволит либо сохранить их, либо отменить изменения в активном документе.

Реализовать описанное поведение лучше всего, если создать функцию, которая будет проверять, изменял ли пользователь текст в редакторе, и спрашивать пользователя, желает ли он отменить либо сохранить изменения.

private
    { Private declarations }
    FOpenedFile: string;
    function CloseCurrentDocument: Boolean;
  public
    { Public declarations }
  end;

function TMainForm.CloseCurrentDocument: Boolean;
begin
  Result := True; {Позволяет пользователю закрыт текущий документ}
  if Memo1.Modified then
  begin
    case MessageDlg('Сохранить изменения в текущем документе?', mtWarning,
                      mbYesNoCancel, 0) of
      mrYes: SaveAction.Execute;
      mrCancel:Result := False;
    end; // Завершение конструкции case
  end;  // Завершение условия if Editor.Modified
end;

Если текст, отображенный в редакторе, не был изменен, функция возвращает True, в результате чего мы можем либо закрыть все приложение, либо заменить текст в редакторе пустым или существующим документом. Если текст в редакторе был изменен, вызывается функция MessageDlg, чтобы пользователь мог сохранить или отменить текст, отображенный в редакторе. Если пользователь щелкает на кнопке Yes (Да), функция сначала инициирует действие Сохранить для сохранения документа и возвращает True, чтобы уведомить о том, что теперь документ можно закрыть. Если пользователь щелкает на кнопке No (Нет), функция возвращает True, поскольку пользователь желает отменить изменения. Наконец, если пользователь щелкает на кнопке Cancel (Отмена), функция возвращает False, чтобы уведомить о том, что нельзя ни закрывать приложение, ни заменять активный документ другим.

Теперь необходимо вызвать функцию CloseCurrentDocument в действиях Новый и Открыть, чтобы спросить пользователя о дальнейших действиях, если в текст были внесены изменения.

procedure TMainForm.NewActionExecute(Sender: TObject);
begin
  if CloseCurrentDocument then
  begin
    Memo1.Lines.Clear;
    FOpenedFile := '';
  end;
end;

procedure TMainForm.OpenActionExecute(Sender: TObject);
begin
  if CloseCurrentDocument and OpenDialog1.Execute then
  begin
    // Сохранение имени выбранного файла
    FOpenedFile := OpenDialog1.FileName;
    // Загрузка выбранного документа
    Memo1.Lines.LoadFromFile(FOpenedFile);
  end;
end;

Последнее, что потребуется делать — это написать обработчик для события OnCloseQuery формы.

Это событие возникает тогда, когда пользователь пытается закрыть форму. Параметр CanClose события OnCloseQuery позволяет определить, может ли форма быть закрыта или нет.

Обработчик события OnCloseQuery на самом деле очень прост. Мы должны всего лишь присвоить результат выполнения функции CloseCurrentDocument параметру CanClose. Таким образом, если функция CloseCurrentDocument вернет значение True, пользователь сможет закрыть приложение. Закрытие формы будет остановлено только лишь в том случае, если текст в редакторе будет изменен, а пользователь щелкнет на кнопке Cancel (Отмена) в диалоговом окне MessageDlg.

procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := CloseCurrentDocument;
end;

Меню Edit

Все команды меню Edit будем создавать вручную.

Отмена

Для начали создадим действие Отменить:

  1. Создайте новое действие.
  2. В поле свойства Caption введите Отменить.
  3. В поле свойства Hint введите Отменить последнее действие.
  4. Присвойте действию имя UndoAction.
  5. Назначьте свойству Shortcut комбинацию Сtrl+Z.

Чтобы отменить действия в редакторе, вы должны вызвать метод Undo. Чтобы узнать, можете ли вы отменить какое-либо действие, необходимо вызвать метод CanUndo. Но лучше всего вызвать метод CanUndo в событии OnUpdate действия, чтобы запретить действие в случае невозможности выполнения отмены.

procedure TMainForm.UndoActionExecute(Sender: TObject);
begin
  Memo1.Undo;
end;

procedure TMainForm.UndoActionUpdate(Sender: TObject);
begin
  UndoAction.Enabled := Memo1.CanUndo;
end;

Назначьте действие UndoAction неименованному пункту в меню Правка.

Вырезание и копирование в буфер обмена

Действия Вырезать и Копировать подобны друг другу. Действие Копировать копирует выделенный текст в буфер обмена, а действие Вырезать сначала копирует выделенный текст в буфер обмена, а затем удаляет текст из редактора.

Поскольку действия Вырезать и Копировать имеют один обработчик события OnUpdate, давайте сначала создадим оба действия, а затем напишем необходимые обработчики событий.

Чтобы создать действие Вырезать, выполните следующие шаги:

  1. Создайте новое действие в редакторе Action List.
  2. В поле свойства Caption нового действия введите Вырезать.
  3. В поле свойства Hint введите Вырезать выделенный фрагмент в буфер обмена.
  4. Присвойте действию имя CutAction.
  5. Назначьте свойству Shortcut комбинацию Ctrl+X.

Чтобы создать действие Копировать, выполните перечисленные ниже шаги:

  1. Создайте новое действие в редакторе Action List.
  2. В поле свойства Caption нового действия введите Копировать.
  3. В поле свойства Hint введите Копировать выделенный фрагмент в буфер обмена.
  4. Присвойте действию имя CopyAction.
  5. Назначьте свойству Shortcut комбинацию Ctrl+C.

Реализовать оба обработчика события OnExecute не составляет особого труда. Чтобы скопировать текст из редактора в буфер обмена, вы должны вызвать метод CopyToClipboard. Чтобы вырезать текст в буфер обмена, вызовите метод CutToClipboard редактора.

procedure TMainForm.CopyActionExecute(Sender: TObject);
begin
  Memo1.CopyToClipboard;
end;

procedure TMainForm.CutActionExecute(Sender: TObject);
begin
  Memo1.CutToClipboard;
end;

Код в обработчике события OnUpdate должен запрещать действие, если в редакторе не будет выделен текст. Для определения, сколько символов было выделено пользователем, можно использовать свойство SelLength редактора. Если значение этого свойства будет равно 0, это значит, что в редакторе нет выделенных символов, и действие должно быть запрещено.

Теперь запишем следующий обработчик события OnUpdate для действия вырезать и назначим его событию OnUpdate действия Копировать:

procedure TMainForm.CutActionUpdate(Sender: TObject);
begin
  TAction(Sender).Enabled := Memo1.SelLength > 0;
end;

Назначьте действия CutAction и CopyAction неименованным пунктам в меню Правка.

Вставка в буфер обмена

Во время действия Вставить содержимое буфера обмена вставляется в редактор. Чтобы ваш редактор был по-настоящему профессиональным, вы должны позволить пользователю выбирать команду Вставить только тогда, когда в буфере обмена будет содержаться хоть какой-нибудь текст. Чтобы узнать, какой формат имеют данные, хранящиеся в буфере обмена, вызовите метод HasFormat.

Чтобы узнать, содержит ли буфер обмена простой текст, который может быть вставлен в редактор, вызовите метод HasFormat и передайте в качестве параметра константу CF_TEXT. Чтобы использовать глобальный объект Clipboard, необходимо добавить модуль Clipbrd в список uses.

Для создания действия Вставить потребуется выполнить следующие шаги:

  1. Создайте новое действие.
  2. В поле свойства Caption нового действия введите Вставить.
  3. В поле свойства Hint введите Вставить текст из буфера обмена.
  4. Присвойте действию имя PasteAction.
  5. Назначьте свойству Вставить комбинацию Ctrl+V.
procedure TMainForm.PasteActionExecute(Sender: TObject);
begin
  Memo1.PasteFromClipboard;
end;

procedure TMainForm.PasteActionUpdate(Sender: TObject);
begin
  PasteAction.Enabled := Clipboard.HasFormat(CF_TEXT);
end;

Назначьте действие PasteAction неименованному пункту в меню Правка.

Удаление

Действие Удалить выполняет практически то же самое, что и действие Вырезать. Подобно Вырезать, действие Удалить удаляет выделенный текст из редактора. Различие между ними состоит в том, что действие Удалить не копирует текст в буфер обмена перед удалением текста из редактора.

Чтобы создать действие Delete, выполните следующие шаги:

  1. Создайте новое действие.
  2. В поле свойства Caption нового действия введите Удалить.
  3. В поле свойства Hint введите Удалить выделенный фрагмент.
  4. Присвойте действию имя DeleteAction.
  5. Назначьте свойству Shortcut клавишу Del.

Для удаления текста из редактора без изменения содержимого буфера обмена применяется метод ClearSelection. Кроме этого, назначьте обработчик события OnUpdate действия Cut событию OnUpdate действия Delete, чтобы позволить пользователю удалять выделенный текст только в том случае, если этот текст существует.

Назначьте действие DeleteAction неименованному пункту в меню Правка.

Выделение всего документа

Пожалуй, наиболее простым из всех действий является Выделить все, которое позволяет выделять все содержимое редактора. Чтобы создать действие Выделить все, выполните следующие шаги:

  1. Создайте новое действие.
  2. В поле свойства Caption нового действия введите Выделить все.
  3. В поле свойства Hint введите Выделить весь документ.
  4. Присвойте действию имя SelectAllAction.
  5. Назначьте свойству Shortcut клавишу Ctrl+A.

Назначьте действие SelectAllAction неименованному пункту в меню Правка.

Чтобы выделить все содержимое компонента ТМеmо, необходимо вызвать метод SelectAll:

procedure TMainForm.SelectAllActionExecute(Sender: TObject);
begin
  Memo1.SelectAll;
end;

Поиск текста в Delphi

Чтобы реализовать команду Найти, сначала добавьте в окно Designer Surface компонент TFindDialog. Компонент TFindDialog заключает в себе обычное диалоговое окно Найти, с помощью которого пользователь может производить поиск строки текста. Строка, которую пользователь пытается найти, хранится в свойстве FindText.

Чтобы пользователь мог осуществлять поиск в тексте, потребуется создать действие Найти, отображающее диалоговое окно Найти, и написать обработчик для события OnFind диалогового окна для реализации поиска. Поскольку диалоговое окно Найти позволяет искать несколько экземпляров строки, мы должны объявить переменную Integer, в которой будет храниться последняя позиция поиска:

private
    { Private declarations }
    FLastSearch: Integer; // последняя позиция поиска
    FOpenedFile: string;
    function CloseCurrentDocument: Boolean;
  public
    { Public declarations }
  end;

Теперь, чтобы создать действие Найти, выполните перечисленные ниже шаги:

  1. В поле свойства Caption нового действия введите Найти.
  2. В поле свойства Hint введите Найти указанный текст.
  3. Присвойте действию имя FindAction.
  4. Назначьте свойству Shortcut комбинацию Ctrl+F.
  5. В обработчик события OnExecute действия поместите следующий код:
procedure TMainForm.FindActionExecute(Sender: TObject);
begin
  // Старт поиска в начале документа
  FLastSearch := 0;
  // Отображение диалогового окна
  FindDialog1.Execute;
end;

Код, отвечающий за выполнение поиска:

procedure TMainForm.FindDialog1Find(Sender: TObject);
var
  memoText: string;
  searchPos: Integer;
  dialog: TFindDialog;
begin
  dialog := TFindDialog(Sender);
  memoText := Memo1.Lines.Text;
  if FLastSearch <> 0 then
    Delete(memoText, 1, FLastSearch);
  searchPos := Pos(dialog.FindText, memoText);
  if searchPos = 0 then
    MessageDlg(Format('Не могу найти "%s"', [dialog.FindText]),
                mtInformation, [mbOK], 0)
  else begin
    Inc(FLastSearch, searchPos);
    Memo1.SelStart := Pred(FLastSearch);
    Memo1.SelLength := Length(dialog.FindText);
    Memo1.SetFocus;
  end;
end;

Первая строка (приведение параметра Sender к типу TFindDialog) необязательна, если в команде Правка - Найти вы намереваетесь использовать только этот метод. В данном случае мы должны выполнить приведение к типу по той причине, что это позволит повторно использовать этот метод в событии OnFind компонента TReplaceDialog.

В следующих двух строках создается временная копия всего документа и удаляется та часть документа, в которой пользователь уже выполнил поиск. Если мы не удалим эту часть, функция Pos, используемая для выполнения поиска, всегда будет возвращать первый экземпляр строки поиска.

Если функция Pos найдет экземпляр строки поиска, мы должны будем сохранить позицию найденного экземпляра в переменной FLastSearch, а затем выделить строку в редакторе. Для выделения строки в редакторе потребуется изменить свойства SelStart и SelLength. Свойство SelStart показывает позицию курсора, а свойство SelLength определяет количество выделенных символов.

Наконец, чтобы показать выделение, мы должны вызвать метод SetFocus для передачи редактору фокуса.

Назначьте действие FindAction неименованному пункту в меню Правка.

Замена текста

В плане завершения работы над меню Правка необходимо создать действие Заменить, которое позволит производить поиск и замену строки. Чтобы реализовать действие Заменить, потребуется выполнить следующие шаги:

  • Добавить в окно Designer Surface компонент TReplaceDialog.
  • Создать действие, которое будет отображать диалоговое окно Заменить.
  • Реализовать обработчики для событий OnFind и OnReplace компонента TReplaceDialog.

Для создание действия Заменить потребуется выполнить перечисленные ниже шаги:

  1. В поле свойства Caption нового действия введите Заменить… .
  2. В поле свойства Hint введите Заменить найденный текст другим текстом.
  3. Присвойте действию имя ReplaceAction.
  4. Назначьте свойству Shortcut комбинацию Ctrl+H.
  5. Присвойте свойству Tag значение 1 или любое другое значение, отличное от 0.
  6. Назначьте обработчик события OnExecute действия Найти событию OnExecute.

Мы должны изменить свойство Tag с целью повторного использования обработчика события OnExecute действия Найти. После того как вы измените свойство Tag действия Заменить, вы можете изменить обработчик события OnExecute действия Найти, чтобы отобразить оба диалоговых окна:

procedure TMainForm.FindActionExecute(Sender: TObject);
begin
  // Старт поиска в начале документа
  FLastSearch := 0;
  if TComponent(Sender).Tag = 0 then
    // Отображение диалогового окна
    FindDialog1.Execute
  else
    ReplaceDialog1.Execute;
end;

Наконец, мы должны реализовать обработчики для события OnFind. которое происходит при щелчке пользователем на кнопке Найти, и события OnReplace, которое происходит при щелчке пользователем на кнопках Заменить или Заменить все.

На самом деле, писать обработчик для события OnFind не потребуется, поскольку можно воспользоваться существующим обработчиком события OnFind компонента TFindDialog. Этот обработчик можно использовать по той причине, что вначале было выполнено приведение параметра Sender к компоненту TFindDialog, а также потому, что TReplaceDialog происходит от класса TFindDialog.

В обработчике события OnReplace необходимо проверить, существует ли выделенный текст в редакторе (SelText <> ''), и если он существует, то заменить его строкой из свойства ReplасеТехt.

procedure TMainForm.ReplaceDialog1Replace(Sender: TObject);
begin
  if Memo1.SelText <> '' then
    Memo1.SelText := ReplaceDialog1.ReplaceText;
end;

Меню Format

Меню Формат в нашем примере приложения является наиболее простым меню. Оно состоит только из двух команд — Перенос по словам и Шрифт.

н1-7

Команда Перенос по словам позволяет переносить текст по правому краю. Если установить галочку напротив этой команды, то вы сможете прокручивать содержимое редактора по вертикали. Если галочка не будет установлена, вы должны будете отображать обе линейки прокрутки, поскольку длинные строки не будут переноситься по правому краю.

Чтобы создать действие Перенос по словам, выполните следующие шаги:

  1. Создайте новое действие и присвойте его свойству AutoCheck значение True, чтобы команда автоматически принимала состояние Checked.
  2. В поле свойства Caption введите Перенос по словам.
  3. Присвойте свойству Checked значение True, поскольку свойство Перенос по словам редактора имеет значение True по умолчанию.
  4. Присвойте действию имя WordWrapAction.

И, наконец, напишите следующий обработчик события OnExecute:

procedure TMainForm.WordWrapActionExecute(Sender: TObject);
const
  SCROLLS: array[Boolean] of TScrollStyle = (ssBoth, ssVertical);
begin
  Memo1.WordWrap := WordWrapAction.Checked;
  Memo1.ScrollBars := SCROLLS[Memo1.WordWrap];
end;

Назначьте действие WordWrapAction неименованному пункту в меню Формат.

Чтобы создать команду Формат - Шрифт, сначала добавьте в окно Designer Surface компонент TFontDialog, а затем создайте новое действие. В поле Caption нового действия введите Шрифт, присвойте действию имя FontAction, a затем напишите следующий код в обработчике события OnExecute:

procedure TMainForm.FontActionExecute(Sender: TObject);
begin
  // Отображение текущего шрифта в диалоговом окне
  FontDialog1.Font.Assign(Memo1.Font);
  // Изменение шрифта
  if FontDialog1.Execute then
    Memo1.Font.Assign(FontDialog1.Font);
end;

Назначьте действие FontAction неименованному пункту в меню Формат.

Отображение подсказок и состояния

Добавьте на форму компонент TStatusBar. Если свойству SimplePanel присвоить значение True, то компонент TStatusBar сможет отображать только одну порцию информации, заданную свойством SimpleText. Однако если свойству SimplePanel присвоить значение False, мы сможем использовать свойство Panels для создания многопанельной строки состояния и отображения большего количества информации для пользователя.

Выберите компонент строки состояния и щелкните на кнопке (...) рядом со свойством Panels, чтобы вывести на экран редактор коллекций Collection Editor.

Щелкните на кнопке Add New (Добавить новую), чтобы создать три панели строки состояния. Присвойте свойству Width первых двух панелей значение 75. чтобы зарезервировать большее пространство для вывода текста.

Первая панель будет служить для отображения количества строк в документе и номера выбранной в данный момент отроки. Вторая панель будет использоваться для отображении идентификатора Modified (Изменено), если содержимое редактора будет изменяться, а последняя панель будет применяться для вывода подсказок.

Наилучшим местом для этого кода является событие OnIdle приложения, поэтому добавьте в окно Designer Surface компонент TApplicationEvents и в обработчик события OnIdle поместите следующий код:

procedure TMainForm.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
const
  MODIFIED: array[Boolean] of string = ('', 'Modified');
begin
  // Состояние строки
  StatusBar1.Panels[0].Text := Format('Линия %d/%d',
      [Succ(Memo1.CaretPos.Y), Succ(Memo1.Lines.Count)]);
  // Измененное состояние
  StatusBar1.Panels[1].Text := MODIFIED[Memo1.Modified];
end;

Чтобы отобразить подсказку в последней панели, подготовьте обработчик для события OnHint:

procedure TMainForm.ApplicationEvents1Hint(Sender: TObject);
begin
  StatusBar1.Panels[2].Text := Application.Hint;
end;

Панель инструментов

Теперь нам осталось сделать всего две вещи: добавить глифы для наиболее часто используемых действий, а затем поместить эти действия в панель инструментов. Для начала добавьте в окно Designer Surface компонент TImageList, присвойте ему имя Normal, а затем добавьте глифы для действий New, Open, Save, Undo, Cut, Copy, Paste, Delete и Find. После того как вы добавите эти изображения в компонент TImageList, назначьте компонент TImageList компонентам TActionList, TToolbar и TMainMenu, после чего откройте редактор Action List и назначьте глифы соответствующим действиям.

После того как вы назначите глифы действиям, выберите панель инструментов и щелкните на ней правой кнопкой мыши, чтобы вывести контекстное меню панели инструментов. Контекстное меню содержит команду New Button (Новая кнопка) для создания новой кнопки панели инструментов, а также команду New Separator (Новый разделитель) для создания разделителя, который позволит визуально распределить кнопки по группам. Все, что вам необходимо сделать сейчас — это добавить несколько кнопок в панель инструментов и назначить действие свойству Action каждой кнопки.

При желании можете также изменить следующие два свойства, чтобы придать панели инструментов более привлекательный вид:

  1. Присвойте свойству AutoSize значение True, чтобы удалить пустое пространство в панели инструментов.
  2. Присвойте свойству ShowCaptions значение True, чтобы отобразить заголовки кнопок (если вы сделаете это, то должны будете удалить символы ам-персанда и точки из заголовков кнопок).

y1-8

Исходный код здесь. Выполнен на Delphi XE.

Источник: Иван Хладни - Внутренний мир Borland Delphi 2006.