Подклассы окон - Программирование, компьютеры и кибернетика лекция

Подклассы окон - Программирование, компьютеры и кибернетика лекция



































Порождение подкласса окон. Правила применения ресурсов приложений. Акселераторы как средство связывания комбинаций клавиш с конкретными действиями, их применение. Меню Windows, его организация. Диалоги, их классы, правила их описания и работа с ними.


посмотреть текст работы


скачать работу можно здесь


полная информация о работе


весь список подобных работ


Нужна помощь с учёбой? Наши эксперты готовы помочь!
Нажимая на кнопку, вы соглашаетесь с
политикой обработки персональных данных

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Сейчас нам надо рассмотреть один интересный прием - порождение подкласса окон. Часто бывает так, что возможностей, предоставляемых окном того или иного стандартного класса Вам не хватает, а создавать эквивалентный стандартному класс с небольшими отличиями слишком сложно. В этом случае было бы удобно научиться создавать дополнительные классы окон, основанные на уже известных классах.
Именно это и называется порождением подкласса окон. Основная идея заключается в использовании собственной функции обработки сообщений, которая выполняла бы требуемую обработку, отличную от стандартной. При этом в качестве процедуры обработки сообщений по умолчанию должна выступать процедура, определенная в уже существующем классе.
Для реализации этого метода нам надо сделать три вещи:
узнать адрес процедуры обработки сообщений заданного окна (или заданного класса).
научиться вызывать нужную процедуру вместо процедуры обработки сообщений по умолчанию.
сделать так, что бы сообщения обрабатывала написанная нами процедура, а не определенная в классе.
Первую и третью задачи удобно решать с помощью функции
LONG SetWindowLong( hWnd, GWL_WNDPROC, lpfnNewProc );
эта функция одновременно устанавливает новый адрес процедуры обработки сообщений и возвращает адрес прежней функции. Конечно, когда мы передаем адрес новой процедуры обработки сообщений он должен быть адресом связанной с нашим приложением функции, то есть он должен быть возвращен процедурой MakeProcInstance .
Теперь нам надо только организовать обращение к старой процедуре обработки сообщений вместо процедуры по умолчанию ( DefWindowProc ). Сделать это непосредственно мы не можем, так как при вызове оконной процедуры мы должны связать ее с приложением, зарегистрировавшем этот класс. Вместо этого нам надо воспользоваться функцией:
LONG CallWindowProc( lpfnProc, hWnd, wMsg, wPar, lPar );
LONG WINAPI ChildProc( HWND, UINT, UINT, LONG );
// функция обработки сообщений главного окна
HWND hWnd, UINT wMsg, UINT wPar, LONG lPar
lpfnNewProc= MakeProcInstance( (FARPROC)ChildProc, hInstance );
BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,
// заменяем процедуру обработки сообщений дочернего окна
lpfnOldProc= (FARPROC)SetWindowLong(
hChild,GWL_WNDPROC,(LONG)lpfnNewProc
return DefWindowProc( hWnd, wMsg, wPar, lPar );
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 информацией о данном классе, а затем создать свой класс, который будет применять вместо процедуры обработки сообщений по умолчанию процедуру этого класса.
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 RemoveProp( hWnd, lpszName );
int EnumProp( hWnd, lpfnEnumProc );
Хотя в документации данные, связанные с конктретным свойством, рассматриваются всегда как хендлы, но это не обязательно так. Конечно применение хендлов может несколько сократить размеры списка свойств за счет того, что одному элементу списка может соответствововать больше данных.
Так как Windows не знает, хендл какого блока данных (глобального или локального), объекта GDI или просто данные связан с конкретным элементом списка свойств, то при удалении записи эти данные не удаляются, а передаются Вам для их удаления.
ResNameId TypeNameId [load-opt] [mem-opt] ResSource
Каждый ресурс должен иметь собственное уникальное имя или номер ResNameId и имя или номер типа ресурса TypeNameId .
Эти имена задаются либо текстом ( имя ), либо числом ( номер ), либо символическим именем ( номер ).
(компилятор ресурсов может использовать директивы препроцессора C и включать заголовочные файлы .H , для задания символических имен).
Далее, при работе с ресурсами они будут загружаться из файла приложения в память. При этом для ресурса обычно выделяется блок глобальной памяти мы можем задать некоторые характеристики ресурса как блока памяти mem-opt и определять некоторые правила его загрузки load-opt .
load-opt , описывая правила загрузки, может быть:
PRELOAD ресурс должен загружаться в памяти при запуске приложения
LOADONCALL ресурс загружается только по требованию ( используется по умолчанию )
mem-opt задает характеристики выделяемого блока и может быть:
FIXED ресурс должен размещаться в фиксированном блоке памяти
MOVEABLE ресурс размещается в перемещаемом блоке памяти ( используется по умолчанию )
DISCARDABLE перемещаемый ресурс может быть удален из памяти (практически любой перемещаемый ресурс может быть удален, так как его содержимое не меняется)
Наконец, нам требуются данные этого ресурса ResSource . Некоторые виды ресурсов должны быть размещены в отдельном файле, в этом случае в качестве ResSource используется имя файла, другие виды ресурсов требуют непосредственного описания непосредственно в файле описания ресурсов, в этом случае ResSource может быть:
Иногда допускается либо использования файлов, либо непосредственное описание ресурсов. Некоторый “разнобой” может быть связан с применением компиляторов (и редакторов) ресурсов разных фирм - так как многие из них используют расширенные возможности.
Так, например, редактор ресурсов Borland WorkShop может описывать практически все ресуры непосредственно в файле описания ресурсов, включая их в виде дампа ресурса, а стандартные компилятор ресурсов Microsoft RC не допускает этого, например, для курсоров или битмапов. Компилятор ресурсов Symantec позволяет применять кавычки при задании имен ресурса или типа, что позволяет составлять имена из нескольких слов, что невозможно для Borland и Microsoft и т.д.
Windows предусматривает несколько стандартных типов ресурсов, а Вы можете легко описать ресурсы собственного типа, указав собственный тип (или номер, больший 255 - номера типов от 0 до 255 зарезервированы Windows). При задании данных собственного ресурса Вы можете указать имя файла, содержащего этот ресурс - тогда этот файл включается в ресурс как он есть, либо описав в виде текста непосредственно в файле описания ресурсов:
“This is a 0-terminated string\0”, 1, 2, 3, 4, 5,
В качестве типа ресурса можно указать стандартный тип RCDATA , который соответствует включаемым в файл описания ресурсов данным пользователя в этом-же формате. Если Вы хотите получить доступ к Вашим ресурсам, то надо воспользоваться парой функций:
HRSRC FindResource( hInstance, lpszName, lpszType );
HGLOBAL LoadResource( hInstance, hrSrc );
Первая функция позволяет получить промежуточный хендл описания ресурса, а вторая - загрузить ресурс память и получить хендл глобального блока памяти, содержащего ресурс. Если Вы декларировали ресурс как LOADONCALL , то физическое размещение ресурса в памяти произойдет не при вызове функции LoadResource , а при непосредственном обращении к ресурсу.
Если для задания имен ресурса или типа вы использовали текст, то параметры lpszName и lpszType являются указателями на соответствующие строки; если же используются номера, то вы можете их указывать двумя способами - передав строку, начинающуюся на # , например, “#123” , либо разместив в младшем слове адреса нужный номер, а старшем 0 . Последний механизм реализуется с помощью макроса:
Этот способ считается самым эффективным, тем более, что Вы можете применять символические имена для задания номеров. При необходимости чтения данных ресурса Вы должны его зафиксировать в памяти с помощью процедуры
LPVOID LockResource( hGlobResource );
и после доступа к данным разрешить его перемещение:
BOOL UnlockResource( hGlobResource );
(Это не отдельная процедура, а обычный GlobalUnlock ). После использования ресурса его можно удалить с помощью процедуры:
BOOL FreeResource( hGlobResource );
Когда Вы применяете ресурсы какого-либо типа, предусмотренного Windows, то приходится применять несколько другие способы доступа к данным, связанные с необходимостью специальной обработки таких ресурсов. Можно выделить следующие основные типы ресурсов:
ACCELERATORS - таблица акселераторов клавиатуры; для загрузки применяется функция
HACCEL LoadAccelerators( hInstance, lpszAccName );
BITMAP - битмап, включенный в приложение для загрузки применяется функция
HBITMAP LoadBitmap( hInstance, lpszBitmapName );
CURSOR - ресурс, представляющий курсор мыши для загрузки применяется функция
HCURSOR LoadCursor( hInstance, lpszCursorName );
DIALOG - диалог с ресурсами типа DIALOG и с самими диалогами мы разберемся позже.
FONT - включение шрифтового ресурса о применении шрифтов мы говорили ранее. Включать ресурс этого типа в Ваше приложение следует специфическим способом, существенно отличающимся от остальных ресурсов.
ICON - иконка для загрузки применяется функция
HICON LoadIcon( hInstance, lpszIconName );
MENU - меню, которое может быть назначено к окну для загрузки применяется функция
HMENU LoadMenu( hInstance, lpszMenuName );
STRINGTABLE - таблица строк ресурс этого типа вообще не загружается целиком. Он представляет собой таблицу строк, имеющих идентификаторы, и обеспечивает доступ к конкретной строке по ее идентификатору. Реально ресурсу этого типа соответствует не блок данных в памяти, а, может быть, несколько - для каждых 16 строк (по порядку номеров) выделяется отдельный блок. Приложение может содержать только один ресурс этого типа, поэтому при описании таблицы строк в файле описания ресурсов ее имя не указывается - указывается только тип этого ресурса. Для доступа к строкам применяется функция
int LoadString( hInstance, idString, lpszBuff, nmaxCount );
Мы достаточно близко познакомились с ресурсами типа BITMAP и FONT ; практически можно считать что мы знакомы и с ресурсами типа CURSOR и ICON , так как они описываются так_же, как и BITMAP . Сейчас нам надо лучше разобраться с тремя новыми типами - ACCELERARTORS , MENU и DIALOG .
Акселераторы представляют собой простейшее средство для связывания определенных комбинаций клавиш с конкретными действиями. Можно считать, что акселераторы представляют собой таблицу, в которой записываются нажимаемые клавиши и генерируемые ими сообщения.
Точнее, акселераторы генерируют только сообщение WM_COMMAND , указывая более подробную информацию в параметрах этого сообщения. Параметр wPar сообщения содержит идентификатор, назначенный клавише, а параметр lPar всегда равен 0x00010000L .
Для создания таблицы акселераторов Вы должны поместить в файле описания ресурсов соответствующий ресурс:
AccName ACCELERATORS [load-opt] [mem-opt]
type тип клавиши ASCII , VIRTKEY или опущен
options указывает состояние специальных клавиш и некоторые действия: NOINVERT , ALT , SHIFT , CONTROL или опущен.
подробнее рассмотрим назначение акселераторов на примере:
“A”, 100 // послать извещение 100 при нажатии А
65, 100, ASCII // то же самое, ASCII код 65 соответствует А
“^A”, 101 // послать 101 при нажатии Ctrl-A
VK_SPACE, 102, VIRTKEY // послать 102 при нажатии Space
VK_SPACE, 103, VIRTKEY, SHIFT // послать 103 при нажатии Shift-Space
Несколько слов следует сказать о применении акселераторов в приложении. Сам факт загрузки акселератора в память еще не обозначает его применения. Для того, что бы сообщения от клавиатуры начали обрабатываться акселератором надо в главном цикле обработки сообщений включить специальлные средства для их трансляции.
int TranslateAccelerator( hWnd, hAccel, lpMSG );
Параметр hWnd указывает окно, которое будет получать извещения, hAccel задает хендл таблицы акселераторов, lpMSG - адрес структуры MSG , содержащей сообщение.
При обычном применении акселератора извлеченное из очереди сообщение передается в эту функцию. Если это сообщение клавиатуры и данное нажатие на клавишу транслируется акселератором, то указанное окно получает сообщение WM_COMMAND и процедура возвращает TRUE ; во всех остальных случаях возвращается FALSE , говоря о том, что сообщение не было трансировано в другое. Считается, что если сообщение было обработано акселератором, то дальнейшая его обработка не требуется - то есть обычный процесс трансляции и диспетчеризации этого сообщения исключается. При этом главный цикл обработки сообщений приобретает следующий вид:
hAccel= LoadAccelerators( hInstance, “AccName” );
while ( GetMessage( &msg, NULL, NULL, NULL ) ) {
if ( !hAccel || !TranslateAccelerator( hWnd, hAccel, &msg ) ) {
Загруженные акселераторы автоматически удаляются при завершении приложения.
При работе с системным меню вместо сообщения WM_COMMAND мы будем получать сообщения WM_SYSCOMMAND . При описании меню в ресурсе текст описания меню должен размещаться в файле описания ресурсов в следующей форме:
определения пунктов меню 0-го уровня:
POPUP для определения пункта, связанного с меню следующего уровня
определение пунктов меню 1-го уровня
Для определения пункта меню, связанного с меню следующего уровня мы должны использовать следующую форму записи:
Для задания обычного пункта меню, то есть посылающего WM_COMMAND при его выборе, мы должны использовать следующую форму записи:
В этих случаях приняты следующие обозначения:
text задает текст пункта меню в виде строки взятой в двойные кавычки, один из символов строки может предваряться символом & , который приводит к подчеркиванию этого символа и его автоматической интерпретации как акселератора.
id определяет идентификатор пункта меню
options указывает на некоторые возможные характеристики данного пункта меню:
CHECKED пункт меню отмечен галочкой. (невозможно для меню 0-го уровня)
INACTIVE пункт меню неактивен (его нельзя выбрать), но рисуется обычным способом
GRAYED пункт меню неактивен и нарисован серым цветом
MENUBREAK пункт меню размещен либо в новой строке (для уровня 0), либо в новом столбце.
MENUBARBREAK то же, что и MENUBREAK , но столбец (строка) отделяется сплошной чертой
HELP обозначает пункт меню, связанный с подсказкой.
Для использования меню совместно с окном мы можем воспользоваться любым удобным способом:
при регистрации класса окна мы можем указать имя требуемого ресурса. Тогда все окна этого класса при создании получат указанное меню.
мы можем указать хендл меню при создании окна, тогда это окно будет создано с указанным меню.
в любой момент мы можем вызвать функцию
с помощью которой мы можем установить новое меню, заменить одно на другое или удалить имеющееся (указав hMenu=NULL ).
Во время работы мы можем легко получить хендл меню, используемого данным окном:
и, зная хендл меню, столь же легко можем узнать хендл меню следующего уровня:
здесь параметр `nPos' указывает номер пункта меню, связанного с меню следующего уровня.
Вы можете создать новое пустое меню, которое можно использовать как в качестве меню верхнего уровня, так и в качестве меню других уровней. Это определяется только его применением. Если Вы его добавите к другому меню, то оно будет POPUP меню, а если Вы его назначите окну, то оно будет меню верхнего уровня. Для создания нового меню предназначена функция
Кроме того мы можем узнать хендл системного меню данного окна:
HMENU GetSystemMenu( hWnd, FALSE );
с помощью которого мы можем добавить новые пункты к системному меню, изменить или удалить прежние. При коррекции меню можно использовать два разных способа задания пункта меню:
по его идентификатору (пункт, связанный с меню следующего уровня не имеет идентификатора, поэтому не может быть указан этим способом).
При выборе этого способа Вы должны указать флаг MF_BYCOMMAND при указании пункта меню.
по его номеру в меню. В этом случае Вы должны указать флаг MF_BYPOSITION при задании пункта.
При необходимости корректировать меню мы можем воспользоваться следующими функциями:
BOOL AppendMenu( hMenu, nFlags, idNew, lpszNewName );
BOOL InsertMenu( hMenu, idItem, nFlags, idNew, lpszNewName );
BOOL ModifyMenu( hMenu, idItem, nFlags, idNew, lpszNewName );
BOOL DeleteMenu( hMenu, idItem, nFlags );
Эти четыре функции позволяют добавлять в конец меню, вставлять, изменять или удалять пункты меню. С их же помощью можно манипулировать с меню следующего уровня - добавлять, изменять или удалять.
BOOL CheckMenuItem( hMenu, idItem, nFlags );
BOOL EnableMenuItem( hMenu, idItem, nFlags );
BOOL HiliteMenuItem( hWnd, hMenu, idItem, nFlags );
С помощью этих функций можно отметить отдельный пункт меню галочкой, запретить его или пометить выделенным. Меню может не перерисовывается после изменений, поэтому Вы должны, окончив все изменения, вызвать процедуру
которая перерисует меню. Конечно, если изменения делались в невидимом пункте меню, то его можно не перерисовывать.
void MapDialogRect( hWndDlg, lpRect );
Первая функция возвращает двойное слово, младшее слово которого содержит размер символа системного шрифта по оси X , а старшее - по оси Y . Разделив эти числа на 4 и 8 Вы можете узнать цену единиц диалога.
Вторая функция преобразует координаты точек прямоугольника из системы координат диалога в систему координат экрана.
int DialogBox( hInstance, lpszDlgTemplate, hWndOwner, lpfnDlgProc );
hInstance, lpszDlgTemplate, hWndOwner, lpfnDlgProc, lParamInit
int DialogBoxIndirect( hInstance, hglbDlgTemplate, hWndOwner, lpfnDlgProc );
hInstance, hglbDlgTemplate, hWndOwner, lpfnDlgProc, lParamInit
HWND CreateDialog( hInstance, lpszDlgTemplate, hWndOwner, lpfnDlgProc );
hInstance, lpszDlgTemplate, hWndOwner, lpfnDlgProc, lParamInit
HWND CreateDialogIndirect( hInstance, hglbDlgTemplate, hWndOwner, lpfnDlgProc );
hInstance, hglbDlgTemplate, hWndOwner, lpfnDlgProc, lParamInit
Для создания диалога необходимо передать соответствующей функции структуру данных, описывающую этот диалог (то есть указывающую стили, размеры, положение и идентификаторы управляющих элементов и самого диалога).
Половина из перечисленных функций, содержащих слово ...Indirect... в названии, использует хендл глобального блока памяти hglbDlgTemplate в котором должна размещаться такая структура. Вы должны сами позаботиться о создании и заполнении этого блока данными.
Другая половина функций, не содержащих слова ...Indirect... в названии, использует имя (номер) ресурса, описывающего эту структуру данных. При этом приложение должно содержать ресурс типа DIALOG , для которого компилатор ресурсов создает нужный блок данных. Вы можете сами загружать ресурс в блок глобальной памяти, что-либо корректировать в нем, если это необходимо, и использовать функцию ...Indirect... для создания диалога.
Кроме информации о самом диалоге Вы должны указать хендл копии приложения, с которой будет связано окно диалога, и которое содержит требуемые ресурсы; хендл окна - пользователя диалога (о различии Owner и Parent мы уже говорили). Помимо этого Вы должны указать адрес процедуры, обрабатывающей сообщения диалога lpfnDlgProc (об этой функции чуть позже). Это должен быть адрес функции, связанной с копией приложения с помощью функции MakeProcInstance .
Когда окно диалога создается, оно дополнительно получит сообщение WM_INITDAILOG , которое используется для инициализации управляющих элементов. Вы можете передать вместе с этим сообщением параметр lParam , содержащий нужные Вам данные. Для этого предназначены функции, содержащие слово ...Param в названии.
while ( GetMessage( &msg, NULL, NULL, NULL ) ) {
if ( !hWndModeless || !IsDialogMessage( hWndModeless, &msg ) ) {
Порядок применения функций IsDialogMessage и TranslateAccelerator определяется желаемым эффектом: если Вам надо, что бы акселераторы использовались диалогом, то трансляцию акселератора надо производить до вызова функции IsDialogMessage . Обычно это не требуется и трансляция производится позже.
В некоторых случаях Вы можете с помощью CreateDialog иммитировать модальный диалог, организовав после создания окна дилога дополнительный цикл обработки сообщений. При этом Вы можете предусмотреть специальную трансляцию некоторых сообщений.
Вы можете применять окна диалога в качестве главных окон приложения.
WM_INITDIALOG инициализация диалога (это сообщение не посылается оконной функции диалога, оно передается только в процедуру диалога)
WM_GETDLGCODE посылается управляющему элементу для выяснения ожидаемых управляющих сообщений
WM_NEXTDLGCTL установка фокуса на требуемый управляющий элемент, сообщение можно только посылать.
WM_PARENTNOTIFY извещение о создании/удалении/”щелчке” мышкой
WM_ENTERIDLE модальный диалог или меню ожидает ввода данных. посылается диалогом или меню главному окну приложения.
DM_GETDEFID узнать идентификатор DEFPUSHBUTTON
DM_SETDEFID выбрать новую DEFPUSHBUTTON
Внимание! сообщения DM_GETDEFID и DM_SETDEFID имеют номера WM_USER и WM_USER+1 , поэтому не используйте собственных сообщений WM_USER и WM_USER+1 для посылки окну диалога!
BOOL CALLBACK _export DlgProc( hWnd, wMsg, wPar, lPar ) {
Функция DlgProc возвращает FALSE , если сообщение надо обрабатывать стандартным образом и TRUE , если сообщение обработано. Единственное исключение - сообщение WM_INITDIALOG , где значение TRUE указывает на необходимость установить фокус на требуемый управляющий элемент, а FALSE говорит о том, что Вы уже установили фокус.
Обычно Вы пишете только DlgProc . Однако эта функция возвращает логическую величину, используемую процедурой DefDlgProc . В некоторых случаях требуется возвращать конкретный конечный результат обработки сообщения (например сообщение WM_QUERYOPEN ).
Вы можете сделать это с помощью функций GetWindowLong и SetWindowLong , указывая смещение DWL_MSGRESULT для чтения/изменения возвращаемого по умолчанию значения.
Кроме того Вы можете изменить при желании адрес функции диалога на новый, используя смещение DWL_DLGPROC для чтения/записи адреса процедуры обработки сообщений.
Эти данные размещены в пространстве, добавляемом к структуре, описывающей окно, при его создании ( DLGWINDOWEXTRA ). Соответственно DWL_MSGRESULT и DWL_DLGPROC имеют положительные значения.
При разработки необходимых функций диалога надо учитывать некоторую разницу между модальным и немодальным диалогами. Все отличия можно свести к нескольким пунктам:
модальный диалог завершается с помощью процедуры
которая возвращает указанный результат и прерывает цикл обработки сообщений, организованный процедурой DialogBox .
немодальный диалог заканчивается при уничтожении окна диалога с помощью обычной функции DestroyWindow . При этом Вы должны принять меры, что бы в главном цикле обработки сообщений больше не вызывалась процедура IsDialogMessage для этого диалога.
так как функция создания немодального диалога возвращает хендл окна диалога, то мы можем обойтись без функции диалога, поступая обычным способом - написав оконную процедуру, использующую в качестве функции обработки сообщений по умолчанию процедуру DefDlgProc . При этом мы указываем NULL в качестве адреса функции диалога и, после создания окна, заменяем адрес процедуры обработки сообщений на собственный (по-сути применяя прием порождения подкласса окон).
При этом обработка сообщений диалога может быть изображена следующей схемой:
Если мы указали адрес функции диалога NULL , то DlgProc , изображенная на этой схеме, вызываться не будет. Рассмотрим небольшой пример:
HWND hWnd, UINT wMsg, UINT wPar, LONG lPar
switch ( wMsg ) // нестандартная обработка сообщений
return DefDlgProc( hWnd, wMsg, wPar, lPar );
lpfnOwnProc= MakeProcInstance( (FARPROC)OwnDlgProc, hInstance );
hModeless= CreateDialog( hInstance, “my_res”, hWndOwner, NULL );
SetWindowLong( hModeless, GWL_WNDPROC, (LONG)lpfnOwnProc );
// Внимание! Так как подстановка процедуры осуществляется после
// создания окна, то первые сообщения, включая WM_INITDIALOG
// уже обработаны стандартной функцией
FreeProcInstance( lpfnOwnDlgProc );
Вообще нам может понадобиться порождать подкласс и от модального диалога. В этом случае подмену процедуры обработки сообщений лучше производить в функции диалога при обработке сообщения WM_INITDIALOG :
LONG PASCAL FAR _export OwnDlgProc(
HWND hWnd, UINT wMsg, UINT wPar, LONG lPar
HWND hWnd, UINT wMsg, UINT wPar, LONG lPar
установить новую оконную процедуру и запретить вызов
SetWindowLong( hWnd, GWL_WNDPROC, (LONG)lpfnOwnProc );
SetWindowLong( hWnd, DWL_DLGPROC, (LONG)NULL );
если мы устанавливаем новую функцию при обработке сообщения
WM_INITDIALOG, то наша новая функция его уже не получит. Поэтому нам
надо послать какое-либо специальное сообщение или вызвать отдельную
функцию для первоначальной инициализации диалога.
lpfnDlgProc= MakeProcInstance( (FARPROC)DlgProc, hInstance );
lpfnOwnProc= MakeProcInstance( (FARPROC)OwnDlgProc, hInstance );
answer= DialogBox( hInstance, “my_res”, hWndOwner, lpfnDlgProc );
FreeProcInstance( lpfnOwnDlgProc );
HWND GetDlgItem( hwndDlg, nCtrlId );
Эти функции позволяют определить идентификатор управояющего элемента диалога по его хендлу или хендл управляющего элемента по его идентификатору и хендлу диалога.
LONG SendDlgItemMessage( hwndDlg, nCtrlId, wMsg, wPar, lPar );
Эта функция используется для посылки сообщения конкретному управляющему элементу диалога.
Следующая группа функций может задавать текст управляющего элемента в виде числа или строки.
void SetDlgItemInt( hwndDlg, nCtrlId, nValue, bSigned );
UINT GetDlgItemInt( hwndDlg, nCtrlId, lpbOk, bSigned );
void SetDlgItemText( hwndDlg, nCtrlId, lpszString );
int GetDlgItemText( hwndDlg, nCtrlId, lpsBuffer, nMaxCount );
Еще несколько функций предназначены для работы с кнопками разных видов:
void CheckDlgButton( hwndDlg, nCtrlId, nCheck );
void CheckRadioButton( hwndDlg, nCtrlFirst, nCtrlLast, nCheck );
UINT IsDlgButtonChecked( hwndDlg, nCtrlId );
Для выбора файлов с помощью списков разного вида. Эти функции одновременно обслуживают список с именами файлов и статический текст, в котором представлен текущий путь:
int DlgDirList( hwndDlg, lpszPath, idListBox, idText, nFileType );
int DlgDirListComboBox( hwndDlg, lpszPath, idComboBox, idText, nFileType );
BOOL DlgDirSelect( hwndDlg, lpszPath, idListBox );
BOOL DlgDirSelectEx( hwndDlg, lpszPath, nMaxCount, idListBox );
BOOL DlgDirSelectComboBox( hwndDlg, lpszPath, idComboBox );
BOOL DlgDirSelectComboBoxEx( hwndDlg, lpszPath, nMaxCount, idComboBox );
При необходимости программной передачи управления могут пригодиться следующие функции:
HWND GetNextDlgGroupItem( hwndDlg, hwndCtrl, bPreviouse );
HWND GetNextDlgTabItem( hwndDlg, hwndCtrl, bPreviouse );
Напоследок несколько особенностей диалога.
Во_первых , надо очень аккуратно применять элемент типа DEFPUSHBUTTON , так как он может “перехватывать” клавишу Enter у других элементов диалога, даже если эта клавиша необходима для их нормальной работы.
Так, если при работе в COMBOBOX вы нажмете Enter для выбора текущего элемента из списка, DEFPUSHBUTTON может перехватить это сообщение, соответственно возьмет на себя фокус ввода, а COMBOBOX отреагирует на это как на отмену выбора элемента.
Во_вторых , могут возникнуть сложности с раскраской управляющих элементов диалога и самой панели далога. Если вы будете обрабатывать сообщение WM_CTLCOLOR функцией диалога, то для возвращения хендла кисти Вам надо устанавливать поле DWL_MSGRESULT структуры окна диалога.
Однако, диалог выполняет некоторую обработку этого сообщения после того, как Вы вернули ответ. При этом он руководствуется своими правилами для назначения кисти и может вовсе заменить назначенную Вами на желаемую им.
При необходимости управлять цветом элементов диалога эффективно может использоваться прием порождения подкласса от диалога - когда Вы можете обрабатывать WM_CTLCOLOR самостоятельно и не использовать стандартной обработки этого сообщения.
Сообщения мыши, работа с ней и ее функции. Основные типы и стили окон и их взаимодействие друг с другом. Статические элементы, кнопки, списки, редактор и полосы прокрутки как стандартные классы дочерних окон. Создание окон нестандартного вида и их цвет. лекция [56,0 K], добавлен 24.06.2009
Основы организации приложения в Windows. Посылка и передача сообщений для окон. Создание и отображение главного окна приложения. Деактивация приложения, его фазы. Сообщения клавиатуры и функции для работы с ней. Определение состояния отдельных клавиш. лекция [65,7 K], добавлен 24.06.2009
Определение окна. Что можно делать в окнах? Термины, употребляемые в описании работы многооконного интерфейса. Виды окон в графическом интерфейсе. Открытие и закрытие окон в различных операционных системах. Вызов контекст
Подклассы окон лекция. Программирование, компьютеры и кибернетика.
Экономический Патронат Реферат
Курсовая работа по теме Влияние экологических факторов на жизнедеятельность организмов
Курсовая работа по теме Розвиток знімальної геодезичної мережі прокладанням теодолітного ходу. Горизонтальне знімання території
Управление Финансовыми Ресурсами Пфр Дипломная
Курсовая работа по теме Генезис и современные проблемы развития экономической теории
Реферат: Властивості ґрунтів
Элементы теории графов. Экономические приложения
Реферат по теме Современные религиозные конфессии славян
Рок Музыка Сочинение
Курсовая работа: Экономика пищевого предприятия
Реферат по теме Конкурс 1401-го года
Народные Традиции Сочинение
Где Найти Дипломные Работы
Курсовая работа по теме Игровые упражнения как способ коррекции коммуникативных умений у детей младшего школьного возраста с ранним детским аутизмом
Реферат: Вплив антропогенних факторів на здоров я людини 2
Реферат: Военное искусство казацких полковников в Освободительной войне украинского народа середины ХУПв. (Воєнне мистецтво козацьких полковників у Визвольній війні українського народу середини ХУІІ ст.)
Курсовая работа по теме Научно-технический прогресс на примере Японии
Курсовая работа по теме Основные фазы и операции мыслительной деятельности
Курсовая Работа На Тему Характеристика И Применение Гексаметилентетрамина
Курсовая работа: Микробная коррозия и ее возбудители
Функции управления, особенности и основные характеристики - Менеджмент и трудовые отношения контрольная работа
Трансплантация. Виды трансплантации. Современные проблемы. Трансплантация зуба - Медицина реферат
Теоретические основы бухгалтерского учёта и аудита денежных средств организации. - Бухгалтерский учет и аудит курсовая работа


Report Page