Для демонстрации возможностей включения в прикладную программу собственных пиктограмм (значков) и курсоров использован видоизмененный соответствующим образом пример 26-1. Приведенный ниже вывод программы (рис. 26-6) отличается от рис. 26.1 только значком в верхнем левом углу окна приложения и формой курсора.
//Приложение 26-4. Пиктограммы и курсоры
//Файл 26-4.rс
myIcon ICON "26-4.ico" //Описание ресурса-значка (ссылка на файл)
myCursor CURSOR "26-4. cur"//Описание ресурса-курсора (ссылка на файл)
//Файл 26-1.срр
#include <owl\framewin.h>
/* Глобальные переменные*/
HICON hIcon;/ /Дескриптор значка
HCURSOR hCursor;// Дескриптор курсора
/*Класс приложения, производный от TApplication (ради InitMainWindow)*/
class MyApp:public TApplication{
public:
virtual void InitMainWindow(void); //Замещаем функцию InitMainWindow
};
/*Класс главного окна, производный от TFrameWindow (ради Paint и GetWindowClass) */ class MyWindow:public TFrameWindow{ public:
MyWindow(TWindow*parent,const char far* title):TFrameWindow(parent,title){
238___________________________________________________ Глава 26
Attr.X=20;Attr.Y=20; //Задаем координаты окна Attr.W=200;Attr.H=60;//Задаем размеры окна
}
void Paint(TDC&,bool,TRect&);//Замещаем открытую функцию TWindow::Paint()
|
|
void GetWindowClass(WNDCLASS&); //Замещаем функцию TWindow::GetWindowClass()
}; /*Замещенная функция InitMainWindow()*/
void MyApp::InitMainWindow(void){
MyWindow* myWin=new MyWindow(0,"Программа 26-4");
SetMainWindow(myWin);
hIcon=LoadIcon("myIcon"); //Загружаем значок и получаем его дескриптор
hCursor=LoadCursor("myCursor") ;//Загружаем курсор и получаем его дескриптор
} /*Замещенная функция Paint ()*/
void MyWindow::Paint(TDC&dc,bool,TRect&){
dc.TextOut(10,10,"Строка текста");
}
/*Замещенная функция GetWindowClass()*/ void MyWindow::GetWindowClass(WNDCLASS& wс){
TWindow::GetWindowClass(wс); //Вызываем исходную функцию GetWindowClass()
we.hIcon=hIcon;//Добавляем в wc дескриптор значка
wc.hCursor=hCursor; //Добавляем в wc дескриптор курсора
} /*Главная функция приложения OwlMain*/
int OwlMain(int,char*[]){
MyApp* myApp=new MyApp;
return myApp->Run(); }
Любое уважающее себя приложение обладает собственным значком, по которому файл приложения можно легко отличить от других программ. Многие приложения (в частности, системы программирования Borland C++, текстовый редактор Word и т.д.) содержат в себе не один, а несколько или даже много значков, из которых пользователь может выбрать наиболее привлекательный. Значок приложения отображается в списке файлов при выводе на экран содержимого той или иной папки (каталога); на панели задач в нижней части Рабочего стола Windows; в левом углу заголовка окна, где этот значок выступает в качестве кнопки для вызова системного меню; в ярлыке приложения на рабочем столе или в какой-либо папке, если таковой ярлык был создан пользователем для облегчения нахождения и вызова приложения. Помимо этого, значки иногда выводятся непосредственно в окно приложения в качестве логотипа или заставки.
|
|
С курсорами ситуация сложнее в том отношении, что приложение, как правило, использует не один, а много курсоров, в зависимости от режима работы и отображаемых на экране окон. Например, в режиме наблюдения, допускающем увеличение, курсор часто приобретает форму лупы; при проходе по окну с текстом, допускающим редактирование, курсор приобретает форму латинской буквы I; процессы, занимающее заметное время, например, чтение или запись файлов, часто меняют форму курсора на изображение песочных или стрелочных часов и т.д. В настоящем разделе приводится простейший пример назначения конкретному окну (в примере - главному) курсора заданной формы.
Новые изображения значка и курсора удобнее всего создать с помощью специализированного редактора ресурсов Resource Workshop, входящего в состав пакетов Borland C++. Файл с изображением значка должен иметь расширение.ICO, файл с изображением курсора - расширение.CUR. Имена обоих файлов описываются в файле ресурсов (в настоящем примере - в файле 26-4.RC, см. текст программы выше). Произвольные имена, с которых начинаются строки описания ресурсов (у нас это myIcon и myCursor) будут в дальнейшем использоваться в программе в качестве идентификаторов ресурсов. В процессе компиляции и сборки программы двоичные представления всех значков и курсоров, описанных в файле ресурсов, включаются в загрузочный модуль приложения; первый из значков используется системой Windows в списках файлов и ярлыках (рис.
26.7), даже если в программе приложения нет никаких обращений к этому ресурсу и он, в сущности, не назначен приложению в качестве его значка.
Для придания окну приложения значка и курсора их следует сначала загрузить в память из загрузочного файла приложения (и получить при этом их дескрипторы), а затем поместить эти дескрипторы в
Обработка сообщения WM_PAINT и интерфейс GDI 239
системную структуру типа WNDCLASS, описывающее данное окно. Поскольку мы будем обращаться к дескрипторам ресурсов из разных функций, они описаны в начале программы, как глобальные переменные hIcon и hCursor. OWL-функции загрузки значка LoadIcon() и курсора LoadCursor() включены в состав класса TModule, поэтому их проще всего вызывать из функций классов, производных от TModule. У нас таким классом является класс приложения МуАрр (см. рис. 25.2), в котором мы переопределили функцию базового класса InitMainWindow(). В текст этой функции можно включить и строки загрузки ресурсов.
Со структурой типа WNDCLASS дело обстоит сложнее, так как во-первых, надо как-то суметь к ней обратиться, и во-вторых, надо сделать это до регистрации класса окна, чтобы сделанные нами исправления зарегистрировались в Windows. Для того, чтобы выполнить требуемую операцию, придется более детально рассмотреть исходные тексты функций OWL, выполняющих создание главного окна приложения (рис. 26.8).
Как уже говорилось, жизнь приложения в значительной степени определяется функцией TApplica-tion::Run(), которая выполняет инициализирующие действия, создает главное окно приложения и организует цикл обработки сообщений. Заместив функцию TApplication::InitMainWindow(), мы получили возможность создать объект myWin класса главного окна MyWindow, а также (в настоящем примере) загрузить необходимые ресурсы - значок и курсор и получить их дескрипторы.
Регистрация класса главного окна выполняется в функции TWindow::Create(), которая вызывает для этого функцию TWindow::Register(). Как видно из рис. 26.8, функция Register() сначала вызывает функцию TWindow::GetWindowClass, назначение которой - заполнить структуру WNDCLASS значениями по умолчанию. Далее вызовом функции API Windows RegisterClass выполнятся регистрация класса окна. Желая изменить настройку структуры WNDCLASS, мы должны заместить функцию класса TWindow GetWindowClass(), подставив на ее место собственную функцию с тем же именем. Это замещение выполняется при описании прикладного класса MyWindow.
|
|
Очевидно, что в нашей функции GetWindowClass() мы прежде всего должны вызвать исходную функцию с тем же именем класса TWindow, чтобы она заполнила все поля структуры WNDCLASS требуемыми по умолчанию значениями. Лишь после этого можно изменить значения отдельных полей нужным нам образом. Следует подчеркнуть, что необходимость вызова исходной, замещенной функции в общем случае совсем не очевидна. Так, например, заместив функцию InitMainWindow(), мы не вызывали исходный вариант, а фактически заново написали ее текст в своей программе с удобными для нас изменениями. Надо ли вызывать замещенные функции из замещающих (и, кстати, когда их вызывать - в начале замещающей функции или, возможно, в конце), а также какие строки допустимо включать в замещающие функции, можно определить, лишь детально рассматривая исходные тексты соответствующих классов OWL.
Наша программа выглядит несколько неуклюже из-за наличия в ней глобальных данных частного характера. Текст программы можно сделать заметно компактнее, если перенести операции загрузки ресурсов с получением их дескрипторов в функцию GetWindowClass(). В этом случае отпадет необходимость объявлять переменные hIcon и hCursor глобальными: их можно переместить в класс MyWindow. Однако функции LoadIcon() и LoadCursor() принадлежат классу TModule, и просто вызвать их из функ-
240 Глава 26
ции класса MyWindow нельзя, необходимо указать объект, для которого они вызываются. В нашей программе указатель на объект производного от TModule класса MyApplication носит название mуАрр, однако в функции GetWindowClass() это конкретное имя, разумеется, не может быть известно. Поэтому придется в процессе выполнения функции GetWindowClass() динамически определить указатель на объект приложения. Это можно сделать с помощью функции класса TWindow GetApplication(), которая возвращает указатель на объект класса TApplication, с которым связано наше окно. Измененный текст функции GetWindowClass() выглядит следующим образом:
void MyWindow::GetWindowClass(WNDCLASS& wc){
|
|
TWindow::GetWindowClass(wc); //Вызываем исходную функцию базового класса wc.hIcon=GetApplication()->TModule::LoadIcon("myIcon"); wc.hCursor=GetApplication()->TModule::LoadCursor("myCursor"); }
Перед функциями LoadIcon() и LoadCursor() пришлось указать их принадлежность к классу TModule, так как мы вызываем их из другого класса. Между прочим, обсуждаемый вариант программы возможен лишь потому, что функции LoadIcon() и LoadCursor() объявлены в классе TModule открытыми. Если бы они были закрытыми или даже защищенными, из другого класса их вызывать было бы нельзя.
Запустив приложение 26-4, можно убедиться в том, что созданный нами значок появляется не только в строке заголовка, но и на панели задач Windows (рис. 26.9).
Рассмотренная процедура придания приложению значка и курсора не является единственной. Придать приложению значок и курсор можно, например, с помощью функций класса TWindow SetIcon() и SetCursor(). Их можно вызывать в замещающей функции InitMainWindow() после образования объекта класса MyWindow. Функции SetIcon() и SetCursor() являются открытыми, однако, чтобы вызывать их из функции, принадлежащей другому классу, необходимо указать конкретный объект, для которого она вызываются, или, как в приведенном ниже фрагменте, указатель на объект:
void MyApp::InitMainWindow(void){
MyWindow* myWin=new MyWindow(0,"Программа 26-4"); SetMainWindow(myWin); myWin->SetIcon(this,"myIcon"); myWin->SetCursor(this,"myCursor"); }
В качестве первого аргумента и той, и другой функции необходимо использовать указатель на объект приложения (производный от класса TModule), для которого осуществляется операция назначения ресурсов. У нас этот указатель будет носить имя mуАрр, однако в функции-члене класса использовать имена конкретных объектов, разумеется, нельзя, а можно только вызывать функции Windows для динамического, в процессе выполнения программы, получения требуемых имен. Здесь, как и в предыдущем фрагменте, можно воспользоваться функцией GetApplication(), вызывав ее для только что созданного указателя myWin
myWin->SetIcon(myWin->GetApplication(),"myIcon");
однако проще и изящнее использовать указатель this (см. предыдущий фрагмент), который в функции, принадлежащей классу МуАрр, как раз и указывает на текущий объект этого класса.