На этом шаге мы рассмотрим создание дочернего окна с характеристиками, заданными пользователем.
Когда вы создаете новое окно, происходящее из TWindow (или из класса, происходящего из TWindow), OWL автоматически регистрирует класс окна Windows. Класс окна в Windows не следует путать с классом окна в OWL. Windows использует оконные классы, чтобы различать типы окон. Этот тип оконного класса включает такие атрибуты окна, как пиктограмму окна, меню, курсор и цвет фона. После регистрации оконного класса в Windows вы можете создавать столько окон, сколько вам необходимо, но это будут окна одного класса. Вы можете рассматривать класс окна для Windows как ксерокопию, описывающую тип окна.
Если вы не изменили Windows-класс своих OWL-окон, OWL задаст этот класс по умолчанию как Windows-класс. Характерные черты таких окон: цвет фона - белый, курсор в виде стрелки, имя класса по умолчанию и возможность реагировать на двойное нажатие кнопки мыши. До тех пор, пока этот задаваемый по умолчанию класс окна удовлетворяет вашим требованиям, вы можете не беспокоиться о регистрации класса окна. Но если вы захотели иметь окно с серым фоном, другим курсором или какими-то особыми атрибутами? В этом случае вы должны зарегистрировать свой собственный класс окна для Windows. Чтобы сделать это, вам необходимо:
Создание нового класса окна под Windows дает вам возможность сделать ваши приложения идеально настраиваемыми, разработав огромное число уникальных типов окон. Чтобы увидеть, как это все делается, запустите программу, приведенную в следующем примере.
#include <owl\applicat.h> #include <owl\framewin.h> #include "pr48_1.rc" //Класс приложения. class TApp: public TApplication { public: TApp():TApplication() {} void InitMainWindow(); }; // Класс главного окна. class TWndw : public TFrameWindow { public: TWndw (TWindow *parent, const char far *title); protected: int childX, childY; void CmOpen(); void CmClose(); DECLARE_RESPONSE_TABLE (TWndw); }; DEFINE_RESPONSE_TABLE1 (TWndw, TFrameWindow) EV_COMMAND (CM_OPEN, CmOpen), EV_COMMAND (CM_CLOSE, CmClose), END_RESPONSE_TABLE; // Класс дочернего окна. class TChildWndw : public TWindow { public: TChildWndw (TWindow *parent, const char far *title, int xCoord, int yCoord); protected: char far *GetClassName(); void GetWindowClass (WNDCLASS &wndClass); }; // TWndw::TWndw() // Это конструктор главного окна. TWndw::TWndw(TWindow *parent, const char far *title): TFrameWindow (parent, title) { // Определить расположение и размеры окна. Attr.X = 20; Attr.Y = 20; Attr.W = 500; Attr.H = 400; // Добавить меню к окну. AssignMenu(MENU_1); // Инициализировать начальную позицию дочернего окна. childX = 75; childY = 75; } // TWndw::CmOpen() // Эта функция вызывается, когда пользователь // выбирает команду Open в меню File. // Она открывает новое дочернее окно. void TWndw::CmOpen() { // Создать новое дочернее окно. TWindow *child = new TChildWndw (this, "Дочернее окно", childX, childY); // Отобразить окно. child->Create(); // Вычислить положение следующего окна. childX += 40; if (childX > 400) childX = 75; childY += 40; if (childY > 300) childX = 75; } // CloseTheWindow() // Функция ForEach вызывает эту функцию, чтобы // закрыть каждое открытое дочернее окно. void CloseTheWindow (TWindow *window, void*) { window->ShutDownWindow(); } // TWndw::CmClose() // Эта функция реагирует на команду Close All меню // File, вызывая итератор ForEach для дочерних окон // из списка дочерних окон TWndw. void TWndw::CmClose() { ForEach(CloseTheWindow); } //************************************ // Реализация класса TChildWndw. //************************************ // TChildWndw::TChildWndw() // Это конструктор дочернего окна. TChildWndw::TChildWndw (TWindow *parent, const char far *title, int xCoord, int yCoord) : TWindow(parent, title) { // Установить тип окна. Attr.Style = WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPSIBLINGS; // Определить расположение и размеры нового окна. Attr.X = xCoord; Attr.Y = yCoord; Attr.W = 200; Attr.H = 150; } // TChildWndw::GetClassName() // Эта функция переопределяет GetClassName() из // TWindow и обеспечивает имя для класса нового окна. char far *TChildWndw::GetClassName() { return "ChildWindow"; } // TChildWndw::GeTWindowClass() // Эта функция переопределяет GetWindowClass() и // устанавливает атрибуты, отличающиеся от атрибутов, // задаваемых по умолчанию, класса окна в OWL. void TChildWndw::GetWindowClass(WNDCLASS &wndClass) { // Разрешить TWindow выполнить его задачу. TWindow::GetWindowClass(wndClass); // Установить курсор для нового окна. wndClass.hCursor = LoadCursor(0, IDC_CROSS); // Установить цвет фона для нового класса. wndClass.hbrBackground = (HBRUSH) GetStockObject (LTGRAY_BRUSH); // Установить пиктограмму для нового класса. TApplication *instance = GetApplication(); wndClass.hIcon = LoadIcon(*instance, "DOC_ICON"); } void TApp::InitMainWindow() { TFrameWindow *wndw = new TWndw (0,"Приложение с дочерними классами"); SetMainWindow(wndw); } int OwlMain(int,char *[]) { return TApp().Run(); }
Файл ресурсов:
#ifndef WORKSHOP_INVOKED #include "windows.h" #endif #define MENU_1 100 #define CM_CLOSE 102 #define CM_OPEN 101 #define CM_EXIT 24310 #ifdef RC_INVOKED MENU_1 MENU { POPUP "&File" { MENUITEM "&Open", CM_OPEN MENUITEM "&Close All", CM_CLOSE MENUITEM SEPARATOR MENUITEM "E&xit", CM_EXIT } } DOC_ICON ICON "doc.ico" #endif
Когда вы запустите программу, представленную в примере, вы увидите главное окно приложения.
Рис.1. Результат работы приложения
При выборе команды Open из меню File появляется новое дочернее окно. Однако эти дочерние окна приложения не являются окнами задаваемого по умолчанию OWL-класса, а, скорее, представляют собой пользовательский оконный класс, имеющий светло-серый фон и курсор в виде перекрестия.
Цвет фона становится видимым с появлением окна. Чтобы увидеть курсор мыши для нового окна, переместите курсор по окну. Когда курсор мыши проходит через одно из дочерних окон, он изменяется на курсор в виде перекрестия. Более того, эти дочерние окна являются официальными дочерними окнами Windows. Это означает, что они имеют атрибут WS_CHILD и не могут быть вынесены за пределы основного окна.
Эта программа похожа на пример из предыдущего шага, за исключением того, что сейчас дочернее окно имеет собственный C++ класс:
class TChildWndw : public TWindow { public: TChildWndw (TWindow *parent, const char far *title, int xCoord, int yCoord); protected: char far *GetClassName(); void GetWindowClass (WNDCLASS &wndClass); };
Помимо конструктора, данный класс включает функции-члены GetClassName() и GetWindowClass(), которые переопределяют функции, наследованные из класса TWindow. Именно эти две функции позволяют вам создать ваш собственный пользовательский оконный класс.
Чтобы создать новый оконный класс, вы должны дать имя этому классу. OWL получает имя класса, вызывал GetClassName():
char far *TChildWndw::GetClassName() { return "ChildWindow"; }
Так как этот класс только возвращает имя нового оконного класса, нет необходимости вызывать TWindow::GetClassName() в вашей переопределенной функции.
OWL возвращает атрибуты нового оконного класса, вызывая GetWindowClass():
void TChildWndw::GetWindowClass(WNDCLASS &wndClass) { // Разрешить TWindow выполнить его задачу. TWindow::GetWindowClass(wndClass); // Установить курсор для нового окна. wndClass.hCursor = LoadCursor(0, IDC_CROSS); // Установить цвет фона для нового класса. wndClass.hbrBackground = (HBRUSH) GetStockObject (LTGRAY_BRUSH); // Установить пиктограмму для нового класса. TApplication *instance = GetApplication(); wndClass.hIcon = LoadIcon(*instance, "DOC_ICON"); }
GetWindowClass() отвечает за заполнение значений структуры WNDCLASS оконного класса. Эта структура содержит значительно больше членов-данных, чем обычно требуется переустанавливать в переопределеной версии этой функции.
Поэтому важно вызвать TWindow::GetWindowClass() до выполнения любых нужных вам изменений. Если вы забудете вызывать TWindow::GetWindowClass(), некоторые важные параметры останутся неинициализированными. С другой стороны, если TWindow::GeTWindowClass() вызван после того, как вы задали все установки, ваши изменения будут перезаписаны значениями, задаваемыми OWL по умолчанию.
WNDCLASS wndClass; // Определить класс окна. wndClass.lpszClassName = "App Name"; wndClass.hInstance = hInstance; wndClass.lpfnWndProc = WndProc; wndClass.hCursor = LoadCursor (NULL, IDC_ARROW); wndClass.hIcon = LoadIcon (hInstance, "ICON"); wndClass.lpszMenuName = NULL; wndClass.hbrBackground = GetStockObject (WHITE_BRUSH); wndClass.style = CS_HREDRAW | CS_VREDRAW; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; // Зарегистрировать класс окна. RegisterClass (&wndClass);
Дополнительную информацию по созданию окон вы можете получить в следующих шагах раздела "Программирование | Язык программирования Ассемблер | 32-битное программирование": 11, 12, 15.
Итак, эта функция сначала вызывает TWindow::GetWindowClass(), после чего она получает дескриптор системного курсора в виде перекрестия. Функция Windows API LoadCursor() имеет два аргумента. Первый из них - дескриптор экземпляра приложения, владеющего курсором. В случае системного курсора первый аргумент должен быть нулевым. Второй аргумент - long - указатель на строку, содержащую имя курсора. IDC_CROSS является предопределенной константой Windows для этого указателя. Более подробно с этими константами вы ознакомитесь в следующей программе. Новый дескриптор курсора заносится в член-данное wndClass.hCursor.
После установки курсора GeTWindowClass() изменяет цвет фона на светло-серый. Для этого запрашивается дескриптор светло-серой кисти и заносится в член-данное wndClass.hbrBackground.
Наконец, программа устанавливает пиктограмму окна в виде пиктограммы документа. Чтобы выполнить эту задачу, программа вызывает функцию-член GetApplication() главного окна, наследуемую из TWindow, для получения указателя на экземпляр приложения. В обращении к LoadIcon() используется разыменованный указатель наряду с именем пиктограммы для получения дескриптора пиктограммы, который затем заносится в член-данное WndClass.hIcon.
На этом новый оконный класс считается инициализированным и готовым для выполнения. Когда окно появляется на экране, оно будет иметь все атрибуты, которые были установлены в GetWindowClass().
На следующем шаге мы рассмотрим изменение курсора мыши.