Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Описатель родительского окна или окна-владельца



Окно может иметь родительское окно. Окно, которое имеет родительское окно, называется дочерним окном (child window). Родительское окно (parent window) предоставляет своим дочерним окнам систему координат для относительного позиционирования. Если у окна есть окно-родитель, то это влияет на его отображение; к примеру, дочернее окно обрезается так, чтобы оно не выходило за пределы родительского окна и (опционально) за пределы клиентской области родительского окна. Окно, у которого нет родителя, либо же родительским окном является окно рабочего стола, называется окном верхнего уровня (top-level window). Приложение может использовать функцию EnumWindows, чтобы получить описатель каждого окна верхнего уровня в системе.

Кроме того, окно может владеть другим окном или иметь окно-владельца (owner window). Владетельное окно всегда появляется поверх своего владельца, оно также сворачивается, когда сворачивается его владелец, и уничтожается, когда уничтожается его владелец.

Описатель меню или идентификатор дочернего окна

Child окно может иметь идентификатор дочернего окна (child-window identifier) - это уникальное число, присваиваемое приложением. Идентификатор дочернего окна особенно полезен для приложений, создающих несколько дочерних окон. Когда приложение создаёт дочернее окно, оно может указать идентификатор для этого окна. После создания окна приложение может поменять идентификатор функцией SetWindowLong или получить его функцией GetWindowLong.

Каждое окно, кроме child-окон, может иметь меню. Приложение может добавить меню в окно, указав описатель меню либо при регистрации оконного класса, либо непосредственно при создании окна.

Описатель экземпляра

Каждый исполняемый модуль (exe или DLL) имеет описатель, ассоциированный с ним. Система использует этот идентификатор, чтобы отличать оконные классы, создаваемые разными модулями.

Пользовательские данные

Каждое окно может иметь ассоциированные с ним пользовательские данные, не используемые системой. Когда создаётся окно, система передаёт указатель на пользовательские данные в оконную процедуру создаваемого окна. Оконная процедура может использовать эти данные для инициализации окна и (опционально) для сохранения данных с окном.

Описатель окна

После создания окна функция создания возвращает оконный описатель (window handle), который уникально идентифицирует окно в системе. Оконный описатель имеет тип HWND. Приложение может использовать этот описатель в других функциях работы с окнами.

Окна в VCL

В Delphi вся работа с окнами заключается в класс-оболочку TWinControl. Формы, кнопки, списки - всё это классы, наследуемые от TWinControl. К примеру: TForm1 -> TForm -> TCustomForm -> TScrollingWinControl -> TWinControl или TButton -> TCustomButton -> TButtonControl -> TWinControl.

У каждого объекта типа TWinControl есть описатель - свойство Handle типа HWND. Этот описатель создаётся по запросу - при первом обращении к свойству Handle. Эту проверку выполняет метод HandleNeeded. Создание описателя выполняет метод CreateHandle, который является обёрткой к методу CreateWnd. Фактически, метод CreateHandle просто вызывает CreateWnd, выполняя пост-настройку объекта после создания окна (настройка якорей и ассоциация объекта TWinControl с окном).

Само создание окна выполняется так: сперва метод CreateWnd строит параметры окна, используя метод CreateParams, который заполняет запись типа TCreateParams. Эти параметры проверяются на допустимость, в них записывается оконная процедура и вызывается метод CreateWindowHandle, который, собственно, и создаёт окно (и является простой обёрткой к функции CreateWindowEx).

Если вы заинтересованы в изменении создаваемого окна, то вы можете заместить метод CreateParams (если вам нужно просто поменять параметры создания окна), CreateWindowHandle (если вы хотите задавать параметры явно вручную), либо CreateWnd (если вы хотите сделать пост-обработку создания окна).

Оконной процедурой (точкой входа) в TWinControl является метод MainWndProc. Этот метод не виртуален, но всё, что он делает - вызывает настоящую оконную процедуру WindowProc, обернув вызов в try/except и вызывая Application.HandleException при ошибке. Именно это - то самое место, в котором вы получаете сообщение об ошибке при исключении в обработчике сообщения (например, нажатия на кнопку) вместо вылета программы. Сама же оконная процедура WindowProc является и вовсе свойством, которое можно присвоить в любое значение (для установки своей оконной процедуры). По умолчанию, WindowProc указывает на (виртуальный) метод WndProc того же объекта. Как правило, если вы хотите дополнить или заменить оконную процедуру, то вы должны заметить метод WndProc в классе-наследнике (если вы хотите выполнить замещение в "вашем" классе), либо изменить свойство WindowProc (если вы хотите изменить поведение внешнего объекта).

Метод WndProc является конечной реализацией оконной процедуры. Собственно, это даже не "изобретение" TWinControl - этот метод появился у предка TWinControl: TControl. TControl является базовым классом для всех элементов управления, необязательно оконных. Оконные элементы управления наследуются от TWinControl.

Таким образом, цепочка вызовов при обработке сообщений выглядит так: MainWndProc -> WindowProc -> WndProc. WndProc может сама обработать сообщение, а может оставить его на обработку по умолчанию. В последнем случае сообщение дополнительно проходит такой путь: WndProc -> Dispatch -> DefaultHandler -> DefWndProc. Метод Dispatch сначала пытается направить сообщение message-методам. И только при их отсутствии - вызывает DefaultHandler. DefWndProc вызывается только для оконных контролов при наличии описателя. Таким образом, если вы заинтересованы в необработанных сообщениях - то вам нужно использовать DefWndProc для окон и DefaultHandler для неоконных контролов.

Заметьте, что Dispatch, DefaultHandler и message-методы вводятся аж в TObject, что означает доступность диспетчеризации сообщений для любого объекта Delphi.

Почти все вышеупомянутые методы являются виртуальными - т.е. доступными для замещения и модификации в классах-наследниках, что позволяет нам менять стандартное поведение в широких пределах.

TComponent (который является предком TControl, а, следовательно и TWinControl) вводит понятие "владельца" компонента (Owner). Заметьте, что это не то же самое понятие, что окно-владелец в терминах системы, как обсуждается выше. Окно-владелец и окно-родитель (в терминах системы) указываются одинаковым образом - как поле WndParent в записи TCreateParams, параметр hWndParent в функции CreateWindowEx и аналогичных местах. То, как трактуется это окно (как родитель или владелец) зависит от типа создаваемого окна (дочернее или верхнего уровня). Поведение этих окон описано выше.

Delphi же вводит понятие владельца в ином смысле. Владелец (в терминах Delphi) - это компонент, который отвечает за удаление владеемого компонента. Его можно указать при создании компонента, либо сменить/задать уже после создания (что бывает редко). При удалении компонента-владельца удаляются и все компоненты, которыми владеет владелец. Вы можете не указывать владельца, если хотите удалять компонент сами, вручную. Как правило, форма является владельцем всех компонентов, размещённых на ней.

Вам не следует путать владельца в терминах системы и владельца в терминах Delphi. Владелец в терминах системы отвечает за взаимодействие окон. Владелец в терминах Delphi не связан с окнами, он контролирует время жизни объекта. Фактически, он применим также и к неоконным элементам управления и даже невизуальным компонентам.

Примечание: Delphi также позволяет вам изменить родительское окно уже после создания объекта. Это позволяет вам сделать "перескакивание" дочернего контрола с одного контейнера (формы, панели) на другой.

Окно Application

Следующий тонкий момент связан со специальным окном Application в Delphi. Как вам должно быть известно, в Delphi есть глобальный объект Application, представляющий собой "приложение". В нём содержатся глобальные параметры и некоторые служебные методы-помощники. Сейчас нас интересует тот факт, что в Application есть окно. Это - служебное окно. Его описатель доступен через свойство Application.Handle. Это окно является обычным окном. Оно видимо, находится на экране (в центре), но... имеет нулевой размер! Так что реально вы его увидеть не можете, не можете и щёлкнуть по нему.

В Delphi принята несколько иная идеология. Кнопка в панели задач представляет собой "приложение", а не отдельное окно. У неё свой заголовок, своя иконка, она сворачивает все окна приложения - и так далее. Поскольку в системе окна работают не так, то Delphi эмулирует такое поведение. Кнопка в панели задач - это, на самом деле, окно Application, а реальные окна программы там не появляются. Все окна приложения имеют владельца - окно Application. Сворачивание приложения на самом деле заключается в скрытии окон (реально сворачивается только окно Application). При этом, конечно же, куча сил уходит на синхронизацию различных состояний между участниками подобной системы. Отсюда идёт множество вопросов вроде "как мне свернуть/развернуть приложение в трей", вопросов про правильную связку окон и им подобных.

Модальные окна

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

Разумеется, такая модель не подходит для Delphi, где вы можете показывать окно различными способами - вызывая Show или ShowModal. Поэтому Delphi не использует системный механизм модальных окон. Вместо этого она эмулирует поведение модальных окон. Когда вы показываете "модальное" окно, VCL отключает все прочие окна в программе, а после окончания показа окна - восстанавливает их доступность. Отключение окна блокирует взаимодействие с пользователем - вы не можете переключиться в окно и вводить в него информацию. Как правило, отключение окна приводит к изменению его вида: окно-контрол показывается "затенённым". Однако окна-формы не изменяют свой вид. Поэтому отключенное окно визуально не отличается от обычного окна. Так что у вас создаётся впечатление, что окно не отключено, а просто сейчас показывается другое (модальное) окно.


 

Тема. Организация взаимодействия форм. Создание многостраничных окон.

Задание: Составить конспект.

План работы:

1 Ознакомиться с перечнем вопросов, подлежащих рассмотрению

2 Ознакомиться с представленным теоретическим материалам

3 Ответить на вопросы для самопроверки

4 Законспектировать ответы на вопросы, подлежащие рассмотрению, привести примеры

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

5.Составляя конспект, записывайте отдельные слова сокращённо, выписывайте только ключевые слова, делайте ссылки на страницы конспектируемой литературы, применяйте условные обозначения.

6.Чтобы форма конспекта отражала его содержание, располагайте абзацы «ступеньками», подобно пунктам и подпунктам плана, применяйте разнообразные способы подчеркивания, используйте карандаши и ручки разного цвета.

Вопросы для самостоятельной работы

1 Добавление новой формы

2 Подключение новой формы

Вопросы для самоконтроля:

1 Какой командой создается новое окно

2 Как подключить модуль нового окна к главному окну

Форма контроля: Оценка составленного конспекта.

 

Теоретический материал

В приложении сложно обойтись одной главной формой. Поэтому приходиться добавлять другие формы и взаимодействовать с ними.

Для того чтобы добавить новую форму в проект заходим в пункт меню File -> New -> Form. Или нажимаем на значок создания новой формы в панели инструментов.

Добавив новую форму, она будет выглядеть также как и основная. При создании форма получит имя Form2 (число обозначает номер создаваемой формы) и связанный модуль формы Unit2. В новую форму можно добавлять компоненты также как и в главную. Но для чтобы дополнительная форма отобразилась в программе нам нужно будет создавать обработчик события.

Мы можем отображать формы в Delphi двумя способами:

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

§ Немодально - пользователь может одновременно работать с несколькими формами.

Для того чтобы отобразить форму модально нужно записать такой код:

Form2.ShowModal;

для не модальной:

Form2.Show;

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

 

 

Поэтому модуль второй формы должен быть включен с помощью зарезервированного слова uses текущего модуля. Проще это сделать выбрав команду File -> Use Unit (файл использовать модуль). Выбрав нужный модуль ссылка на него автоматически добавиться.

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

 

 

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

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

Form2.Caption := Edit1.Text;

Form2.ShowModal;

Запустив программу и нажав на кнопку, мы откроем вторую форму модально, заголовок у нее будет взят из свойства Text компонента Edit первой формы.


[1]Модель – некоторое физическое или логическое (искусственное или естественное) образование (предмет или явление), которое обладает свойствами и поведением, подобными (сходственными) свойствам и поведению другого образования, называемого оригиналом (аналогом).

[2] Согласно принятому в DELPHI соглашению имена классов обычно (но необязательно!) начинаются с префикса T, а имена полей – с префикса F (или f). Смысл ключевых слов private, public поясняется ниже.

[3] Всю объектную базу DELPHI можно просмотреть в окне BrowseObjectsкомандой системы программирования View| Browserпосле компиляции проекта.


Поделиться:



Последнее изменение этой страницы: 2019-04-11; Просмотров: 184; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.03 с.)
Главная | Случайная страница | Обратная связь