Практическое занятие № 16
Тема: "Создание многодокументного редактора"
Цель занятия: получить практические навыки со созданию программ с MDI интерфейсом и использованию компонента RichEdit
Ход работы
1. Создать главную MDI форму вида:

Окно имеет меню с перечнем команд: Файл - (Создать, Открыть..., Выход), Окно - (Каскадом, Слева направо, Сверху вниз).
Указания: для формы задайте свойства: Caption=Текстовый редактор, FormStyle=fsMDIForm, WindowState=wsMaximized (окно будет развернуть на весь экран).
На форму нанесите компонент MainMenu (Standard). Щелкните два раза на компоненте и введите названия нужных пунктов меню.
В меню Окно должен отображаться список открытых дочерних окон. Для этого в свойстве WindowMenu формы укажите имя раздела меню Окно.
2. Создать дочернюю форму вида:

Форма содержит многострочный компонент RichEdit. В заголовке формы отображается номер документа. При открытии дочерней формы в главном меню происходит добавление новых разделов и команд: Файл - (Создать, Открыть..., Сохранить, Сохранить как..., Закрыть, Выход), Правка - (Отменить, Вырезать, Копировать, Вставить, Выделить все), Формат - (Шрифт, Выравнивание (Влево, По центру, Вправо), Список).
Указания: с помощью кнопки NewForm
создайте новую форму. Для формы задайте свойство
FormStyle=fsMDIChild. Форма будет создаваться
динамически. Выполните команду Project - Options.
На закладке Forms перенесите форму
Form2 в список
Available forms.
Так как форма будет создаваться динамически, то для ее удаления из памяти после закрытия в событии OnClose формы введите код:
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
action:=cafree;
end;
Нанесите на форму компонент RichEdit (Win32). Для компонента задайте свойства: Align=alClient (растягиваем поле на всю форму), Lines очистить.
Для создания меню нанесите на форму компонент MainMenu (Standard). Двойным щелчком откройте редактор меню и создайте нужные пункты меню как указано в задании. Для команды Выравнивание нужно создать подменю. Для этого щелкните на команду Выравнивание правой кнопкой и выберите команду Create Submenu.
При открытии дочерней формы необходимо, чтобы соответствующие пункты встраивались в меню главной формы. Для этого каждому разделу меню на дочерней формы в свойстве GroupIndex присвойте порядковые номера: Файл=1, Правка=2, Формат=3.
Нумерацию нужно проставить и для разделов главного меню. С
помощью кнопки ViewForm
перейдите на главную форму
Form1, двойным щелчком на компоненте
MainMenu отройте редактор меню и присвойте номера
для разделов: Файл=1, Окно=4.
Для корректного открытия и сохранения содержимого файлов опишем внутри класса дочерней формы текстовое поле для запоминания имени файл. Перейдите в код дочерней формы, найдите описание класса формы ( TForm2 = class(TForm)) и в разделе public опишите поле класса:
fname:string;
3. Для пунктов меню главной формы напишите код, выполняющий соответствующие действия.
Указания: в разделе Interface модуля формы опишем глобальную переменную для нумерации открытых дочерних форм.
kol_child:integer=0;
Для команды Создать напишем код вида:
procedure TForm1.N5Click(Sender: TObject);
begin
//создаем дочернюю форму
form2:=tform2.create(nil);
form2.show;
form2.repaint;
//наращиваем счетчик дочерних форм на 1
kol_child:=kol_child+1;
//в заголовке дочерней формы отображаем ее номер
form2.caption:='Документ: '+inttostr(kol_child);
end;
Для открытия файлов добавим на форму компонент OpenDialog (Dialogs) и зададим свойства: DefaultExt=rtf, Filter=Форматированный текст|*.rtf |Обычный текст|*.txt.
Если в диалоге открытия файла пользователь указал тип "Форматированный текст", то текст должен загружаться с форматированием. Если же указан тип "Обычный текст", то текст должен загружаться без форматирования. Для этого в событии OnTypeChange компонента OpenDialog напишем код:
procedure TForm1.OpenDialog1TypeChange(Sender: TObject);
begin
//если в диалоге выбран первый фильтр (форматированный текст)
if opendialog1.filterindex=1 then
//открываем текст с форматированием
form2.richedit1.plaintext := false
//иначе, если в диалоге выбран другой фильтр (обычный текст)
else
//иначе сохраняем текст без форматирования
form2.richedit1.plaintext := true;
end;
Для команды Открыть напишем код:
procedure TForm1.N6Click(Sender: TObject);
begin
//если в диалоге открытия файла была нажата кнопка Открыть
if opendialog1.execute=true then
begin
//создаем новое дочернее окно
form2:=tform2.create(nil);
form2.show;
form2.repaint;
//в дочернее окно в компонент richedit загружаем выбранный файл
form2.RichEdit1.Lines.LoadFromFile(opendialog1.filename);
//в специальную переменную запоминаем имя загруженного файла
form2.fname:=opendialog1.filename;
//в заголовке окна отображаем имя открытого файла
form2.caption:=extractfilename(opendialog1.filename);
//компоненту richedit ставим отметку, что файл не редактировался
form2.RichEdit1.Modified:=false;
end;
end;
Для команды Выход напишем код:
procedure TForm1.N7Click(Sender: TObject);
begin
//закрываем главную форму (завершаем работу программы)
form1.close;
end;
Для команды Каскадом напишем код:
procedure TForm1.N4Click(Sender: TObject);
begin
//упорядочиваем дочерние формы каскадом
cascade;
end;
Для команды Слева направо напишем код:
procedure TForm1.N9Click(Sender: TObject);
begin
//упорядочиваем дочерние формы слева направо
tilemode:=tbVertical;
Tile;
end;
Для команды Сверху вниз напишем код:
procedure TForm1.N10Click(Sender: TObject);
begin
//упорядочиваем дочерние формы сверху вниз
tilemode:=tbHorizontal;
Tile;
end;
Запретим выход из программы пока будут открыты дочерние окна. Для этого в событии OnCloseQuery формы напишем код:
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
//если есть открытые дочерние окна
if mdichildcount>0 then
begin
//выдаем сообщение
application.MessageBox('Закройте все дочерние окна перед выходом из программы','Выход невозможен',mb_ok+mb_iconstop);
//запрещаем закрытие окна программы
canclose:=false;
end;
end;
4. Для команд меню дочерней формы написать код, выполняющий соответствующие действия.
Указания: Команда Создать должна выполнять те же действия, что и аналогичная команда в меню главной формы. Поэтому код для команды может иметь вид:
procedure TForm2.N5Click(Sender: TObject);
begin
//запускаем тот же код, что и для команды Создать главной формы Form1
//при условии, что команда Создать имеет имя N5
Form1.N5Click(sender);
end;
Команда Открыть должна выполнять те же действия, что и аналогичная команда в меню главной формы. Поэтому код для команды может иметь вид:
procedure TForm2.N6Click(Sender: TObject);
begin
//вызываем процедуру для команды открыть главной формы Form1
//при условии, что команда Открыть имеет имя N6
Form1.N6Click(Sender);
end;
Для сохранения файла добавьте на форму компонент SaveDialog (Dialogs) и задайте свойства DefaultExt=rtf, Filter=Форматированный текст|*.rtf |Обычный текст|*.txt.
Если в диалоге открытия файла пользователь указал тип "Форматированный текст", то текст должен сохраняться с форматированием и с расширением "rtf". Если же указан тип "Обычный текст", то текст должен загружаться без форматирования и с сохранением "txt". Для этого в событии OnTypeChange компонента SaveDialog напишем код:
procedure TForm2.SaveDialog1TypeChange(Sender: TObject);
begin
//если в диалоге выбран первый фильтр (форматированный текст)
if savedialog1.filterindex=1 then
begin
//сохраняем текст с форматированием
richedit1.plaintext := false;
//то к имени файла будет подставляться расширение rtf
savedialog1.defaultext:='rtf';
end
//если в диалоге выбран другой фильтр (обычный текст)
else if savedialog1.filterindex=2 then
begin
//иначе сохраняем текст без форматирования
richedit1.plaintext := true;
//будет подставляться расширение txt
savedialog1.defaultext:='txt';
end;
end;
Для команды Сохранить как... напишем код:
procedure TForm2.N8Click(Sender: TObject);
begin
//будем обращаться к активному дочернему окну
with (form1.ActiveMDIChild as tform2) do
begin
//если в окне сохранения файла нажата кнопка Сохранить
if savedialog1.execute=true then
begin
//содержимое окна записывается в файл
richedit1.Lines.SaveToFile(savedialog1.filename);
//в переменную запоминается имя файла
fname:=savedialog1.filename;
//в заголовке окна отображается имя файла
caption:=extractfilename(savedialog1.filename);
//делается отметка, что файл не редактировался (уже сохранен)
richedit1.Modified:=false;
end;
end;
end;
Для команды Сохранить напишем код:
procedure TForm2.N7Click(Sender: TObject);
begin
//если переменная с именем файла не пустая,
//то это значит, что файл либо был открыт с диска,
//либо его уже сохраняли
if fname<>'' then
begin
//сохраняем изменения в этот файл
richedit1.Lines.SaveToFile(fname);
//делаем отметку, что файл не изменялся (уже сохранен)
richedit1.modified:=false;
end
//если же переменная с именем файла пустая,
//то это значит, что файл новый
else
//вызываем процедуру для команды меню Сохранить как...
//при условии, что команда Сохранить как... имеет имя N8
Form2.N8Click(Sender);
end;
Для команды Закрыть напишем код:
procedure TForm2.N10Click(Sender: TObject);
begin
//закрываем текущее окно
close;
end;
Команда выход делает те же действия, что и аналогичная команда в меню главной формы. Код для команды может иметь вид:
procedure TForm2.N11Click(Sender: TObject);
begin
//запускаем тот же код, что и для команды Выход главной формы Form1
//при условии, что команда Выход на главной форме имеет имя N7
Form1.N7Click(Sender);
end;
Для команды Отменить напишем код:
procedure TForm2.N13Click(Sender: TObject);
begin
//отменяем последнее действие
richedit1.Undo;
end;
Для команды Вырезать напишем код:
procedure TForm2.N15Click(Sender: TObject);
begin
//вырезаем выделенный фрагмент в буфер обмена
richedit1.CutToClipboard;
end;
Для команды Копировать напишем код:
procedure TForm2.N16Click(Sender: TObject);
begin
//копируем выделенный фрагмент в буфер обмена
richedit1.CopyToClipboard;
end;
Для команды Вставить напишем код:
procedure TForm2.N17Click(Sender: TObject);
begin
//вставляем содержимое буфера обмена в позицию курсора
richedit1.PasteFromClipboard;
end;
Для команды Выделить все напишем код:
procedure TForm2.N19Click(Sender: TObject);
begin
//выделяем весь текст
RichEdit1.SelectAll;
end;
Для форматирования текста добавьте на форму компонент FontDialog (Dialogs). Для команды Шрифт напишем код:
procedure TForm2.N20Click(Sender: TObject);
begin
//вызываем диалог форматирования шрифта
if fontdialog1.execute=true then
richedit1.selattributes.Assign(fontdialog1.Font);
end;
Для команды Выравнивание - Влево напишем код:
procedure TForm2.N22Click(Sender: TObject);
begin
//выравнивает текст влево
richedit1.paragraph.alignment:=taLeftJustify;
end;
Для команды Выравнивание - По центру напишем код:
procedure TForm2.N23Click(Sender: TObject);
begin
//выравнивает текст по центру
richedit1.paragraph.alignment:=taCenter;
end;
Для команды Выравнивание - Вправо напишем код:
procedure TForm2.N24Click(Sender: TObject);
begin
//выравнивает текст вправо
richedit1.paragraph.alignment:=taRightJustify;
end;
Для команды Список напишем код:
procedure TForm2.N25Click(Sender: TObject);
begin
//если списка нет
if richedit1.paragraph.Numbering=nsNone then
begin
//делаем текст списком
richedit1.paragraph.Numbering:=nsBullet;
//ставим флажок для нужного пункта меню
//при условии, что команда Список имеет имя N25
n25.checked:=true;
end
//если список есть
else
begin
//убираем список из текста
richedit1.paragraph.Numbering:=nsNone;
//снимаем флажок для нужного пункта меню
//при условии, что команда Список имеет имя N25
n25.checked:=false;
end;
end;
При закрытии формы нужно проверять, сохранено ли содержимое окна. Если нет, то выдавать запрос на сохранение или отмену сохранения текста.
Для этого в событии OnCloseQuery формы напишем код:
procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
//если содержимое поля отмечено как изменившееся,
//то это значит, что изменения не сохраняли
if richedit1.Modified =true then
//выдаем запрос на сохранение и обрабатываем ответ
case application.MessageBox(pchar('Сохранить изменения в файле '+fname+'?'), 'Сохранение данных', mb_YesNoCancel+mb_iconquestion) of
//если пользователь ответил Да,
//то вызываем код для команды меню Сохранить
//при условии, что команда Сохранить имеет имя N7
idyes: N7Click(Sender)
//если пользователь ответил Отмена,
//отменяем закрытие окна дочерней формы
idcancel: canclose:=false;
end;
end;
5. Создадим форму для регистрации в программе:

Указания: с помощью кнопки NewForm
добавьте новую форму. Для формы задайте свойства:
BorderStyle=bsDialog, Caption=Регистрация.
На форму нанесите компонент Label (Standard) и задайте свойство Caption=Пароль.
На форму нанесите компонент Edit (Standard) и задайте свойства: PasswordChar=*, Text очистить.
На форму нанесите компонент Button (Standard) и задайте свойство Caption=Войти.
Форма регистрации должна запускаться первой, однако MDI форма всегда должна быть главной в проекте. Следовательно окно регистрации должно запускаться до старта основного приложения через файл проекта.
Выполните команду Project-Options и перенесите форму регистрации в список Available Forms.
В коде формы регистрации опишите глобальную вспомогательную переменную. Она будет играть роль признака ввода верного пароля: если пароль верный, то переменная = 1, иначе - 0.
//по умолчанию предполагаем, что пароль не верный
key: integer=0;
Для кнопки напишем код:
procedure TForm3.Button1Click(Sender: TObject);
begin
//если пароль равен заданному
if edit1.text='111' then
begin
//активируем переменную-признак
key:=1;
//закрываем окно регистрации
Close;
end
//если пароль не верный
else
begin
//выдаем сообщение
Application.MessageBox('Пароль неверный. Доступ запрещен.','Ошибка регистрации',MB_OK+MB_ICON_EROR);
//ставим курсор в поле для повторного ввода
Edit1.SetFocus;
end;
end;
Добавим для формы регистрации анимационный эффект появления от центра и исчезновения в центр.
Указания: в событии OnShow формы введите код:
procedure TForm3.FormShow(Sender: TObject);
begin
//окно появляется из точки в центре на протяжении 1 секунды
AnimateWindow(Handle,1000, AW_Center);
end;
При закрытии формы нужно не только указать анимационный эффект, но и проверить значение переменной key. В событии OnClose формы введите код:
procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//окно исчезает в центр в точку на протяжении 1 секунды
AnimateWindow(Handle,1000, AW_Hide or AW_Center);
//если переменная key=0 (пароль не верный)
if key=0 then
//завершаем работу приложения
Application.Terminate;
end;
Появление формы регистрации должно происходить до запуска главной программы.
Указания: с помощью команды Project - View Source откройте файл проекта. После ключевого слова BEGIN введите код:
//создаем в памяти форму регистрации
form3:=TForm3.Create(nil);
//отображаем ее в модальном виде,
//т.е. далее команды не выполняются пока окно не будет закрыто
form3.ShowModal;