48065 (Подклассы окон)

2016-07-30СтудИзба

Описание файла

Документ из архива "Подклассы окон", который расположен в категории "". Всё это находится в предмете "информатика" из , которые можно найти в файловом архиве . Не смотря на прямую связь этого архива с , его также можно найти и в других разделах. Архив можно найти в разделе "книги и методические указания", в предмете "информатика, программирование" в общих файлах.

Онлайн просмотр документа "48065"

Текст из документа "48065"

Подклассы окон

Сейчас нам надо рассмотреть один интересный прием - порождение подкласса окон. Часто бывает так, что возможностей, предоставляемых окном того или иного стандартного класса Вам не хватает, а создавать эквивалентный стандартному класс с небольшими отличиями слишком сложно. В этом случае было бы удобно научиться создавать дополнительные классы окон, основанные на уже известных классах.

Именно это и называется порождением подкласса окон. Основная идея заключается в использовании собственной функции обработки сообщений, которая выполняла бы требуемую обработку, отличную от стандартной. При этом в качестве процедуры обработки сообщений по умолчанию должна выступать процедура, определенная в уже существующем классе.

Для реализации этого метода нам надо сделать три вещи:

  • узнать адрес процедуры обработки сообщений заданного окна (или заданного класса).

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

  • сделать так, что бы сообщения обрабатывала написанная нами процедура, а не определенная в классе.

Первую и третью задачи удобно решать с помощью функции

LONG SetWindowLong( hWnd, GWL_WNDPROC, lpfnNewProc );

эта функция одновременно устанавливает новый адрес процедуры обработки сообщений и возвращает адрес прежней функции. Конечно, когда мы передаем адрес новой процедуры обработки сообщений он должен быть адресом связанной с нашим приложением функции, то есть он должен быть возвращен процедурой MakeProcInstance.

Теперь нам надо только организовать обращение к старой процедуре обработки сообщений вместо процедуры по умолчанию (DefWindowProc). Сделать это непосредственно мы не можем, так как при вызове оконной процедуры мы должны связать ее с приложением, зарегистрировавшем этот класс. Вместо этого нам надо воспользоваться функцией:

LONG CallWindowProc( lpfnProc, hWnd, wMsg, wPar, lPar );

Итак, приведем небольшой пример:

static HANDLE hInstance;

static FARPROC lpfnNewProc;

static FARPROC lpfnOldProc;

LONG WINAPI ChildProc( HWND, UINT, UINT, LONG );

// функция обработки сообщений главного окна

LONG WINAPI _export WinProc(

HWND hWnd, UINT wMsg, UINT wPar, LONG lPar

) {

static HWND hChild;

switch ( wMsg ) {

case WM_CREATE:

lpfnNewProc= MakeProcInstance( (FARPROC)ChildProc, hInstance );

hChild= CreateWindow(

BUTTON”, “Btn A”,

BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,

10,10, 50,50,

hWnd, 0, hInstance, NULL

);

// заменяем процедуру обработки сообщений дочернего окна

lpfnOldProc= (FARPROC)SetWindowLong(

hChild,GWL_WNDPROC,(LONG)lpfnNewProc

);

break;

case WM_DESTROY:

DestroyWindow( hChild );

FreeProcInstance( lpfnNewProc );

break;

...

}

return DefWindowProc( hWnd, wMsg, wPar, lPar );

}

LONG WINAPI _export ChildProc(

HWND hWnd, UINT wMsg, UINT wPar, LONG lPar

) {

// специфичная обработка сообщений

// и вызов прежней функции, а не функции DefWindowProc

return CallWindowProc( lpfnOldProc, hWnd, wMsg, wPar, lPar );

}

Конечно, рассмотренный нами вариант не единственный. Так, например, мы можем заменять функцию обработки сообщений не окна, а класса. Тогда все вновь создаваемые окна этого класса будут применять нашу процедуру. Для этого мы должны использовать функцию

LONG SetClassLong( hWnd, GCW_WNDPROC, lpfnNewProc );

Что неудобно, так это то, что мы должны сначала создать окно, а только затем заменять процедуру обработки сообщений. Мы можем поступить и иначе - сначала узнать адрес процедуры обработки сообщений, используя функцию

GetClassInfo( hInstance, lpszClassName, lpWndClass );

которая заполняет структуру WNDCLASS информацией о данном классе, а затем создать свой класс, который будет применять вместо процедуры обработки сообщений по умолчанию процедуру этого класса.


Связывание данных с окном

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

Для такого связывания в Windows предусмотрено два разных метода. Первый метод основан на выделении дополнительного пространства для данных пользователя в структуре, описывающей окно или класс окон. Этот способ достаточно эффективен, но ограниченно применим, так как выделенное пространство статично и не может изменить свой размер.

Для использования данных окна (или класса) мы должны, при регистрации класса окон указать размеры дополнительного пространства, выделяемого в струткуре окна (поле .cbWndExtra структуры WNDCLASS) и в структуре класса (поле .cbClsExra). При выделении пространства оно автоматически обнуляется. Подробнее об этом смотри лекцию 2.

Для доступа к элементам описаний класса и окна можно применять функции:

UINT GetWindowWord( hWnd, nOffset );

LONG GetWindowLong( hWnd, nOffset );

UINT SetWindowWord( hWnd, nOffset, wNewValue );

LONG SetWindowLong( hWnd, nOffset, dwNewValue );

UINT GetClassWord( hWnd, nOffset );

LONG GetClassLong( hWnd, nOffset );

UINT SetClassWord( hWnd, nOffset, wNewValue );

LONG SetClassLong( hWnd, nOffset, dwNewValue );

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

Второй метод основан на применении специального списка свойств (property) окна. Этот список может динамически изменяться, но работа с ним медленее, чем с данными окна. Кроме того он размещается в локальной памяти модуля USER, поэтому ограничен размерами свободной памяти модуля USER.

Так как списки свойств размещаются не в нашем приложении, то перед уничтожением окна, мы должны удалить все внесенные нами свойства. Свойства состоят из имени (строка символов) и слова данных. Часто это слово рассматривается как хендл блока данных. Мы можем записывать читать, удалять и перебирать свойства, связанные с окном. Для этого предназначены следующие функции:

BOOL SetProp( hWnd, lpszName, hData );

HANDLE GetProp( hWnd, lpszName );

HANDLE RemoveProp( hWnd, lpszName );

int EnumProp( hWnd, lpfnEnumProc );

Хотя в документации данные, связанные с конктретным свойством, рассматриваются всегда как хендлы, но это не обязательно так. Конечно применение хендлов может несколько сократить размеры списка свойств за счет того, что одному элементу списка может соответствововать больше данных.

Так как Windows не знает, хендл какого блока данных (глобального или локального), объекта GDI или просто данные связан с конкретным элементом списка свойств, то при удалении записи эти данные не удаляются, а передаются Вам для их удаления.


Ресурсы приложения

На предыдущих лекциях мы довольно часто ссылались на такие ресурсы приложения, как курсоры и иконки, ранее мы познакомились более подробно с еще одной разновидностью ресурсов - битмапом. На примере битмапа мы рассмотрели основные правила применения ресурсов.

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

Описание ресурсов имеет следующий вид:

ResNameId TypeNameId [load-opt] [mem-opt] ResSource

Каждый ресурс должен иметь собственное уникальное имя или номер ResNameId и имя или номер типа ресурса TypeNameId.

Эти имена задаются либо текстом (имя), либо числом (номер), либо символическим именем (номер).

Примеры:

MYBITMAP BITMAP my_bmp.bmp

100 ICON my_ico.ico

MYDATA 500 my_data.dat

#define IconID 101

IconID ICON second.ico

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

Далее, при работе с ресурсами они будут загружаться из файла приложения в память. При этом для ресурса обычно выделяется блок глобальной памяти мы можем задать некоторые характеристики ресурса как блока памяти mem-opt и определять некоторые правила его загрузки load-opt.

load-opt, описывая правила загрузки, может быть:

PRELOAD ресурс должен загружаться в памяти при запуске приложения

LOADONCALL ресурс загружается только по требованию (используется по умолчанию)

mem-opt задает характеристики выделяемого блока и может быть:

FIXED ресурс должен размещаться в фиксированном блоке памяти

MOVEABLE ресурс размещается в перемещаемом блоке памяти (используется по умолчанию)

DISCARDABLE перемещаемый ресурс может быть удален из памяти (практически любой перемещаемый ресурс может быть удален, так как его содержимое не меняется)

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

BEGIN

данные ресурса

END

или

{

данные ресурса

}

Иногда допускается либо использования файлов, либо непосредственное описание ресурсов. Некоторый “разнобой” может быть связан с применением компиляторов (и редакторов) ресурсов разных фирм - так как многие из них используют расширенные возможности.

Так, например, редактор ресурсов Borland WorkShop может описывать практически все ресуры непосредственно в файле описания ресурсов, включая их в виде дампа ресурса, а стандартные компилятор ресурсов Microsoft RC не допускает этого, например, для курсоров или битмапов. Компилятор ресурсов Symantec позволяет применять кавычки при задании имен ресурса или типа, что позволяет составлять имена из нескольких слов, что невозможно для Borland и Microsoft и т.д.

Windows предусматривает несколько стандартных типов ресурсов, а Вы можете легко описать ресурсы собственного типа, указав собственный тип (или номер, больший 255 - номера типов от 0 до 255 зарезервированы Windows). При задании данных собственного ресурса Вы можете указать имя файла, содержащего этот ресурс - тогда этот файл включается в ресурс как он есть, либо описав в виде текста непосредственно в файле описания ресурсов:

MyResource MyType

BEGIN

This is a 0-terminated string\0”, 1, 2, 3, 4, 5,

100, 0x1000

END

В качестве типа ресурса можно указать стандартный тип RCDATA, который соответствует включаемым в файл описания ресурсов данным пользователя в этом-же формате. Если Вы хотите получить доступ к Вашим ресурсам, то надо воспользоваться парой функций:

HRSRC FindResource( hInstance, lpszName, lpszType );

HGLOBAL LoadResource( hInstance, hrSrc );

Первая функция позволяет получить промежуточный хендл описания ресурса, а вторая - загрузить ресурс память и получить хендл глобального блока памяти, содержащего ресурс. Если Вы декларировали ресурс как LOADONCALL, то физическое размещение ресурса в памяти произойдет не при вызове функции LoadResource, а при непосредственном обращении к ресурсу.

Если для задания имен ресурса или типа вы использовали текст, то параметры lpszName и lpszType являются указателями на соответствующие строки; если же используются номера, то вы можете их указывать двумя способами - передав строку, начинающуюся на #, например, “#123”, либо разместив в младшем слове адреса нужный номер, а старшем 0. Последний механизм реализуется с помощью макроса:

Свежие статьи
Популярно сейчас
Зачем заказывать выполнение своего задания, если оно уже было выполнено много много раз? Его можно просто купить или даже скачать бесплатно на СтудИзбе. Найдите нужный учебный материал у нас!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
5167
Авторов
на СтудИзбе
438
Средний доход
с одного платного файла
Обучение Подробнее