На этом шаге мы рассмотрим создание MDI-приложений.
Автоматическое создание форм
Динамическое создание форм
MDI-свойства TForm
MDI-события и MDI-методы TForm
Пример MDI-приложения
Термин MDI (Multiple Document Interface) дословно означает многодокументный интерфейс и описывает приложения, способные загрузить и использовать одновременно несколько документов или объектов. Примером такого приложения может служить диспетчер файлов (File Manager).
Обычно MDI-приложения состоят минимум из двух форм - родительской и дочерней. Свойство родительской формы FormStyle установлено равным fsMDIForm. Стиль дочерней формы - fsMDIChild.
Родительская форма служит контейнером, содержащим дочерние формы, которые заключены в клиентскую область и могут перемещаться, изменять размеры, минимизироваться или максимизироваться. В приложении могут быть дочерние формы разных типов, например одна - для обработки изображений, а другая - для работы с текстом.
В MDI-приложении, как правило, требуется выводить несколько экземпляров классов формы. Поскольку каждая форма представляет собой объект, она должна быть создана перед использованием и освобождена, когда в ней больше не нуждаются. Delphi может делать это автоматически, а может предоставить эту работу программисту.
По умолчанию при запуске приложения Delphi автоматически создает по одному экземпляру каждого класса форм в проекте и освобождает их при завершении программы. Автоматическое создание обрабатывается генерируемым Delphi кодом в трех местах.
Первое - раздел интерфейса в файле модуля формы.
type TForm1 = class (TForm) private {Закрытые объявления.} public {Открытые объявления.} end;
Вторым является место, в котором описывается переменная класса:
var Form1: TForm1; .
Здесь описана переменная Form1, указывающая на экземпляр класса TForm1 и доступная из любого модуля. Обычно она используется во время работы программы для управления формой.
Третье место находится в исходном тексте проекта, доступ к которому можно получить с помощью меню View | Project Source. Этот код выглядит как:
Application.CreateForm(TForm1, Forml); .
Процесс удаления форм обрабатывается с помощью концепции владельцев объектов: когда объект уничтожается, автоматически уничтожаются все объекты, которыми он владеет. Созданная описанным образом форма принадлежит объекту Application и уничтожается при закрытии приложения.
Хотя автоматическое создание форм полезно при разработке однодокументных приложений, при создании MDI-приложении оно, как правило, неприемлемо.
Для создания нового экземпляра формы используйте конструктор Create класса формы. Приведенный ниже код создает новый экземпляр TForm1 во время работы программы и устанавливает его свойство Caption равным New Form:
Form1:= TForm1.Create(Application); Form1.Caption:= 'New Form'; .
Конструктор Create получает в качестве параметра-потомка объект типа TComponent, который будет владельцем формы. Обычно в качестве владельца выступает Application. Это делается для того, чтобы все формы были автоматически закрыты по окончанию работы приложения. Можно также в качестве параметра использовать значение Nil, создав, тем самым, форму без владельца. Однако в этом случае закрывать и уничтожать ее должен программист. В случае возникновения необрабатываемой ошибки такая форма останется в памяти.
Даже при динамическом создании форм Delphi попытается "помочь" в создании экземпляра каждой формы. Чтобы отказаться от них, нужно в диалоговом окне Project Options (вызывается при выполнении пункта меню Project | Options) удалить классы форм из списка Auto-create forms:
Рис.1. Окно Project | Options
Если требуется получить доступ к отдельному дочернему экземпляру класса, используйте свойство MDIChildren, описываемое в следующем разделе.
Объект TForm имеет несколько свойств, специфичных для MDI-приложений. Перечислим их.
procedure TfrmMDIParent.spbtnClearClick(Sender: TObject); begin if not (ActiveMDIChild = Nil) then if ActiveMDIChild is TfrmMDIChild then TfrmMDIChild(ActiveMDIChild).memDailyNotes.Clear; end;
В первой строке проверяется, равен ли ActiveMDIChild значению Nil, так как в этом случае обращение к объекту вызовет исключительную ситуацию.
Поскольку ActiveMDIChild возвращает объект TForm, компилятор не имеет доступа к memDailyNotes - объекту TfrmMDIChild. Вторая строка проверят соответствие типов, то есть действительно ли свойство ActiveMDIChild указывает на объект TfrmMDIChild. Третья строка выполняет преобразование типа и вызывает метод Clear компонента memDailyNotes.
Обычно это свойство используется при выполнении какого-либо действия над всеми открытыми дочерними формами. Вот код сворачивания всех дочерних форм при щелчке на кнопке с именем Button1:
procedure TForm1.Button1Click(Sender: TObject); var iCount: Integer; begin for iCount:= MDIChildCount-1 downto 0 do MDIChildren[iCount].WindowState:= wsMinimized; end;
Если сворачивать окна в порядке возрастания элементов массива, цикл будет работать некорректно, так как после сворачивания каждого окна массив MDIChildren обновляется и пересортировывается, и в этом случае можно пропустить некоторые элементы.
Для вывода списка TMenuItem должно быть меню верхнего уровня. Это меню имеет свойство Caption, равное sWindow.
В MDI-приложении событие OnActivate запускается только при переключении между дочерними формами. Если фокус ввода передается из не MDI-формы в MDI-форму, генерируется событие OnActivate родительской формы, хотя ее свойство Active никогда и не устанавливается равным True. Эта странность на самом деле строго логична: ведь, если бы OnActivate генерировался только для дочерних форм, не было бы никакой возможности узнать о переходе фокуса ввода от другого приложения.
Специфичные для MDI-форм методы перечислены ниже:
Создадим приложение, позволяющее просматривать графические изображения на отдельной форме. Для этого в новом проекте у формы зададим следующие свойства:
Поместим компонент TPanel в форму. Установим у него следующие свойства:
Поместим компонент TSpeedButton в TPanel и зададим у него следующие свойства:
Добавим в форму компонент TOpenDialog и установим следующие его свойства:
Теперь создадим дочернюю форму. Выполним пункт меню File | New | Form и появится пустая форма. Установим следующие ее свойства:
Поместим компонент TImage во вновь созданную форму и установим его следующие свойства:
Удалим дочернюю форму из списка автоматически создаваемых форм следующим образом:
Создав интерфейс, перейдем к написанию исходного текста приложения.
Сначала загрузим изображение. Следующий код будет размещаться в обработчике события OnClick компонента spbtnLoad:
procedure TfrmMDIParent.spbtnLoadClick(Sender: TObject); begin if opndlgLoad.Execute then with TfrmMDIChild.Create(Application) do begin Caption:= opndlgLoad.FileName; imgMain.Picture.LoadFromFile(opndlgLoad.FileName); ClientWidth:= imgMain.Picture.Width; ClientHeight:=imgMain.Picture.Height; end; end;
После запуска диалогового окна создается новый экземпляр дочерней формы и загружается файл изображения. После загрузки размеры дочерней формы изменяются так, чтобы можно было видеть все изображение.
Поскольку модуль ссылается на тип TfrmMDIChild, находящийся в модуле MDIChild, то после строки implementation следует добавить еще одну строку:
uses MDIChild; .
Теперь можно приступить к компиляции и запуску приложения. Однако по щелчку на кнопке Close дочерняя форма не закрывается, а сворачивается в пиктограмму. Чтобы заставить ее закрыться, следует в код обработчика OnClose класса TfrmMDIChild внести изменение свойства Action:
procedure TfrmMDIChild.FormClose(Sender: TObject; var Action: TCloseAction); begin Action:=caFree; //Закрытие формы. end;
Внешний вид работающего приложения изображен на рисунке 2.
Рис.2. Внешний вид приложения
Текст этого примера можно взять здесь.
Со следующего шага мы начнем знакомиться с графической системой Delphi.
Автоматическое создание форм
Динамическое создание форм
MDI-свойства TForm
MDI-события и MDI-методы TForm
Пример MDI-приложения