Будь умным!


У вас вопросы?
У нас ответы:) SamZan.net

Работа с окнами приложений

Работа добавлена на сайт samzan.net:


Сообщения мыши, работа с мышью

Отдельно надо рассмотреть работу с мышью. Обычно, когда курсор мыши находится над каким-либо окном, это окно получает сообщения от мыши, причем внешний вид курсора мыши определен при регистрации класса окна - поле .hCursor структуры WNDCLASS. Если мы хотим использовать мышь в нашем приложении, то мы должны обрабатывать некоторые сообщения, посылаемые мышью.

WM_NCHITTEST  y & x

При перемещения мыши через область, занятую окном, окно получает сообщения WM_NCHITTEST, которые используются для того, что бы определить месторасположение мыши - на рамке, в углах рамки, на заголовке, во внутренней области и пр. Это должно быть определено при обработке данного сообщения и возвращаемый результат характеризует положение курсора мыши. Например HTCLIENT указывает, что курсор находится над внутренней областью окна, HTTOPLEFT - над верхним левым уголком рамки окна, размеры которого могут быть изменены и пр. Положение курсора указано в координатах экрана.

WM_NCMOUSEMOVE wHitTest y & x

Если WM_NCHITTEST определяет, что курсор находится над внешней областью окна, то окно получает сообщения WM_NCMOUSEMOVE; Y и X координаты заданы относительно экрана.

WM_NCLBUTTONDOWN wHitTest y & x
WM_NCLBUTTONUP wHitTest y
& x
WM_NCRBUTTONDOWN wHitTest y
& x
WM_NCRBUTTONUP wHitTest y
& x
WM_NCMBUTTONDOWN wHitTest y
& x
WM_NCMBUTTONUP wHitTest y
& x
WM_NCLBUTTONDBLCLK wHitTest y
& x
WM_NCRBUTTONDBLCLK wHitTest y
& x
WM_NCMBUTTONDBLCLK wHitTest y
& x

Эти сообщения посылаются при нажатии/отпускании соответствующих кнопок мыши над внешней областью окна; Положение курсора указано в координатах экрана, wParam указывает зону, над которой произошло данное событие.

WM_MOUSEMOVE nKeys y & x

Когда мышь перемещается во внутренней области окна (WM_NCHITTEST возвратило HTCLIENT) то оконная процедура обрабатывает поступающие сообщения WM_MOUSEMOVE, указывающие положение мыши в координатах окна и состояние некоторых клавиш (ctrl, shift и три кнопки мыши).

WM_LBUTTONDOWN nKeys y & x
WM_LBUTTONUP nKeys y
& x
WM_RBUTTONDOWN nKeys y
& x
WM_RBUTTONUP nKeys y
& x
WM_MBUTTONDOWN nKeys y
& x
WM_MBUTTONUP nKeys y
& x

Эти сообщения посылаются окну, если Вы нажали одну из кнопок мыши, когда курсор находится над окном. Параметр nKeys указывает состояние некоторых клавиш.

WM_LBUTTONDBLCLK nKeys y&x
WM_RBUTTONDBLCLK nKeys y&x
WM_MBUTTONDBLCLK nKeys y&x

Это сообщения о двух быстрых нажатиях на одну кнопку мыши. Обычно окно их не получает. Если Вы хотите использовать эти сообщения, то Вы должны при регистрации класса окна указать стиль CS_DBLCLKS.

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

Вы можете легко изменять внешний вид курсора, изменяя его хендл в структуре класса окна:

UINT SetClassWord( hWnd, GCW_HCURSOR, hNewCursor );

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

HCURSOR LoadCursor( hInstance, lpszCursor );

HCURSOR CreateCursor(

hInstance, xHotSpot, yHotSpot, nWidth, nHeight, lpvAND, lpvXOR

);

BOOL DestroyCursor( hCursor );

Функция LoadCursor загружает стандартный курсор или определенный Вами, CreateCursor создает новый курсор с помощью двух масок - lpvAND и lpvXOR, которые позволяют описать четырехцветный курсор - черный, белый, цвет фона, инвертированный фон. В применении этой функции есть только одинподводный камень- ширина и высота создаваемого курсора должны совпадать с требованиями драйвера. Для этого их надо предварительно узнать с помощью функции

int  GetSystemMetrics( SM_CXCURSOR );

int  GetSystemMetrics( SM_CYCURSOR );

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

Вы можете легко показать или спрятать курсор с помощью функции

int  ShowCursor( bShow );

Вы можете установить или узнать позицию курсора с помощью функции

void SetCursorPos( nX, nY );

void GetCursorPos( lpPoint );

Также можно ограничить зону перемещения курсора с помощью функции

void ClipCursor( lpRect );

Еще одна функция,

HCURSOR SetCursor( hCursor );

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

В некоторых случаях бывает удобно применять так называемыйзахваткурсора.Захваченыйкурсор может перемещаться по всему окну, но сообщения от мыши поступают только в то окно, которое захватило курсор. При окно не получает сообщений WM_NCHITTEST, WM_NCMOUSEMOVE и пр., а получает сообщения как бы от внутренней области окна. Конечно, делать такое нужно на небольшое время, например для реализации механизмаПеренести и положить” (Drag And Drop). Только одно окно может захватывать курсор в данное время.

Длязахватываниякурсора предназначены следующие функции:

HWND SetCapture( hWnd );

void ReleaseCapture( void );

Функция SetCapture возвращает хендл предыдущего окна, использовавшегозахватв это время, либо NULL.

Разновидности окон: дочерние, родительские, используемые (owned)

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

Окно создается с помощью функции

HWND CreateWindow(

lpszClassName, lpszTitle, dwStyle,

nX, nY, nWidth, nHeight,

hwndParent, hMenu, hInstance, lpvParam

);

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

Самый общий вид окнаперекрывающиеся (overlapped). Такое окно создается, если указать стиль WS_OVERLAPPED или WS_OVERLAPPEDWINDOW при создании окна. Эти окна всегда имеют рамку (border), заголовок (title-bar) и внутреннюю область. Окна этого стиля применяются в качестве главных окон приложения, при этом настоятельно рекомендуется использовать стиль WS_OVERLAPPEDWINDOW, который описывает стандартное главное окно приложения с кнопками системного меню, максимизации и минимизации.

Близкая к перекрывающимся категория оконвсплывающие (popup) окна, задается указанием стиля WS_POPUP при создании окна. Всплывающие окна отличаются от перекрывающихся тем, что могут не иметь заголовка (title bar). В остальном их применение аналогично.

Если при создании перекрывающихся или всплывающих окон определить хендл окнародителя, то такие окна окажутся в специфических отношениях, называемых отношениями пользователя (owner) и используемого (owned) окон.

Главная идея таких отношений связана с совместным позиционированием в Zнаправлении: окно - пользователь всегда находится непосредственно под используемым окном, при перемещении одного из них в Zнаправлении, другое перемещается вслед за ним. Перемещение окон в X и Y направлениях не взаимосвязано, используемые окна могут находиться вне окна-пользователя. Кроме того, если окно-пользователь становится невидимым или минимизируется, то используемые им окна становятся невидимыми. При уничтожении окна-пользователя все используемые окна автоматически уничтожаются.

В Windows существует одна особенностьхотя при создании используемого окна объявляется хендлродительскогоокна, но при попытке получить хендл родительского окна (например, функцией GetParent), возвращается NULL.

Еще одна большая категория окондочерние (child) –окна, создаются при указании стиля WS_CHILD и хендла родительского окна (parent). Дочерние окна обязательно имеют внутреннюю область, но могут не иметь рамки и заголовка; у них не может быть меню - этот параметр функции CreateWindow задает необязательный идентификатор дочернего окна.

Отношения дочерних и родительских окон напоминают отношения пользователя и используемого, но имеют некоторые отличия:

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

Если Вы хотите избежать этого, то Вам надо указать стиль WS_CLIPCHILDREN при создании окна-родителя.

Зная хендл дочернего окна можно узнать хендл родителя, если воспользоваться одной из двух функций:

HWND GetParent( hwndChild );

HWND GetWindowWord( hwndChild, GWW_PARENT );

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

BOOL EnableWindow( hWnd, bEnable );

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

BOOL ShowWindow( hWnd, SW_HIDE );

BOOL ShowWindow( hWnd, SW_SHOW );

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

Стиль окна влияет, в основном, только на его внешний вид, а свойства окна определяются оконной процедурой. Оконная процедура описывается при регистрации класса окон, а когда создается новое окно мы должны указать имя класса, к которому это окно принадлежит. До сих пор мы сами описывали и регистрировали класс окон и затем создавали окно, принадлежащее этому классу.

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

BOOL UnregisterClass( lpszClassName, hInstance );

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

Стандартные классы дочерних окон

Сейчас мы рассмотрим несколько классов дочерних окон, предоставляемых Windows. Окна этих классов позволяют создавать наиболее часто используемыеуправляющие элементы- кнопки, полосы прокрутки (scroll bars), простейшие редакторы для ввода текста и пр.

Обычно стандартные управляющие элементы создаются со стилtем WS_VISIBLE и, обязательно, - WS_CHILD. Часто используется стиль WS_BORDER. Для многих классов предусмотрен стиль, указывающий, что родительское окно должно извещаться о таких событиях дочернего окна, как, например, получение и потеря фокуса ввода. Название этого стиля оканчивается на _NOTIFY, например, LBS_NOTIFY.

Дочерние окна, принадлежащие к стандартным классам, обмениваются данными с родительским окном по следующим правилам:

  •  родительское окно при необходимости посылает доченему окну сообщения с номерами, равными или большими WM_USER. Для каждого стандартного класса дочерних окон определены свои сообщения, на которые они реагируют. Многие из таких сообщений должны вернуть результат, поэтому часто используется SendMessage вместо PostMessage.
  •  дочернее окно посылает родительскому окну сообщения WM_COMMAND, со следующим назначением параметров:

wPar   – идентификатор дочернего окна
LOWORD(lPar) –хендл дочернего окна
HIWORD(lPar) –код извещения

код извещения информирует родительское окно о том, какое событие произошло с дочерним окном. Посылка некоторых извещений от дочерних окон может быть запрещена - если не указывать ???_NOTIFY стиль. Для каждого класса дочерних окон определены свои коды извещения.

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


Статические элементы

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

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

SS_BLACKRECTчерный закрашенный прямоугольник

SS_BLACKFRAMEчерный контур прямоугольника

SS_GRAYRECT  –серый закрашенный прямоугольник

SS_GRAYFRAMEсерый контур прямоугольника

SS_WHITERECTбелый закрашенный прямоугольник

SS_WHITEFRAMEбелый контур прямоугольника

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

Мы можем описать статический элементпиктограмму (иконку), указав стиль SS_ICON. В качестве заголовка окна задется имя ресурса типа ICON, включенного в Ваше приложение. Размеры определяются размерами иконки независимо от указанных Вами.

Если нам надо заменить одну иконку на другую, то надо этому дочернему окну послать сообщение (STM_SETICON, hIcon, 0L), а если мы хотим только узнать хендл иконки, то надо послать сообщение (STM_GETICON, 0, 0L). Оба сообщения возвращают хендл иконки.

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

SS_SIMPLE, SS_LEFT, SS_LEFTNOWORDWRAP, SS_RIGHT, SS_CENTER

При этом надо обратить внимание на стиль SS_NOPREFIX; Обычно последовательность из & и любого символа обозначает подчеркнутый символ. Однако это не всегда удобно - например, если выводимый текст является именем файла или директории (в этом случае & может содержаться в строке как обычный символ). Для того, что бы запретить использование & в качестве префикса, используется стиль SS_NOPREFIX.

Кнопки

Самыйбогатыйкласс - класс кнопок. Для создания окна, принадлежащего этому классу надо указать имя класса “BUTTON. Большинство кнопок (но не все) являются активными элементами (то есть могут принимать фокус ввода). Обычно кнопки посылают родительскому окну только один код извещения - BN_CLICKED, указывающий на то, что кнопка была нажата. Все остальные коды извещения кнопок (BN_???) соответствуют частному случаю кнопок, который не рекомендуется использовать в Windows 3.1.

К этому классу принадлежат следующие разновидности управляющих элементов:

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

BS_CHECKBOX и BS_AUTOCHECKBOX обозначают флажокэлемент, который состоит из небольшого квадрата и строки текста. В квадрате может быть поставлен крестик (check mark) - то есть этот элемент являетсядвухпозиционным переключателем- отмечен/неотмечен.

BS_AUTOCHECKBOX отличается от обычного флажка тем, что автоматически переключается из одного состояния в другое при нажатии на него, а для простого BS_CHECKBOX вы должны сами подать команду для переключения.

BS_3STATE и BS_AUTO3STATE очень похож на флажок, но может быть в трех состояниях - отмечен/неотмечен/запрещен (в запрещенном состоянии не принимает сообщения от клавиатуры и мыши и рисуется серым. Это состояние включается и выключается только программным способом).

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

BS_GROUPBOX редставляет собой прямоугольную рамку, в верхней части которой может быть выведен текст. Используется для визуального объединения нескольких управляющих элементов в одну группу. Хотя GroupBox и является кнопкой, но он не может получать фокус ввода - то есть больше похож на статические элементы.

Кнопки могут обрабатывать 5 специфичных сообщений:

BM_SETCHECK nCheck L

устанавливает состояние кнопки:
неотмечена
отмечена
запрещена (только BS_3STATE и BS_AUTO3STATE)

BM_SETSTATE nState L

устанавливает состояние кнопки
нормальное состояние
выделена (изобразить кнопку внажатомсостоянии)

BM_SETSTYLE wStyle bRedraw & 0 

изменить стиль кнопки. wStyle является комбинацией BS_??? стилей, а bRedraw указывает, надо ли перерисовать кнопку.

BM_GETCHECK  L
BM_GETSTATE
 L

возвращают текущее состояние кнопки.

Списки

Простые списки относятся к классу LISTBOX. Элементы этого класса представляют собой один или несколько столбцов, в которых размещается список строк. Вы можете выбрать одну или несколько записей из списка для дальнейшего использования. Список может иметь или не иметь полосу прокрутки, строки в нем могут быть отсортированы или размещены в порядке поступления.

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

LB_RESETCONTENT  L

это сообщение приводит к удалению всех данных из списка.

LB_ADDSTRING  lpszString

добавить строку в конец списка

LB_FINDSTRING nIndexStart lpszString

найти нужную строку в списке и получить ее индекс

LB_DELETESTRING nIndex L

удалить строку из списка

LB_GETTEXT nIndex lpsBuffer

прочитать строку с индексом nIndex в списке и разместить ее в указаном буфере.

LB_GETCURSEL  

получить индекс текущего выбранного элемента

LB_DIR nAttr lpszMask

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

Посылаемые родительскому окну коды извещения могут информировать его о следующих событиях списка:

  •  LBN_ERRSPACEо произошедшей ошибке, связанной с нехваткой памяти;
  •  LBN_KILLFOCUS и LBN_SETFOCUSо получении или потере фокуса ввода;
  •  LBN_DBLCLKо двойном нажатии на кнопку мыши;
  •  LBN_SELCHANGEоб изменении текущего выбранного элемента;
  •  LBN_SELCANCELпроцесс выбора прерван, например, переходом к другому окну.

Существует еще одна разновидность списков - так называемые комбинированные списки, состоящие из небольшого окошка редактора и простого списка, размещенного под ним. Эти списки принадлежат к классу COMBOBOX. Выделяют три разновидности комбинированных списков, определяемых его стилем:

  •  простой комбинированный списокCBS_SIMPLEкогда и редактор и список постоянно видны;
  •  выпадающий комбинированный списокCBS_DROPDOWNкогда постоянно видимо окошко редактора и специальная кнопка справа, при нажатии на которую под редактором появляется (выпадает) список.
  •  неизменяемый комбинированный списокCBS_DROPDOWNLISTаналогичный CBS_DROPDOWN, но текст в редакторе не может быть изменен.

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

Такой список может иметь стиль CBS_OEMCONVERT, который приводит к автоматическому преобразованию записываемых в него строк из OEM в ANSI, и к обратному преобразованию при чтении из него данных.

Комбинированные списки поддерживают еще больше сообщений и кодов извещения, связанных с применением редактора и возможностью появления и скрывания списка.

Редактор

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

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

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

Окошко редактора может быть использовано для редактирования небольшого текста, тогда для его чтения или задания удобно использовать функции

void SetWindowText( hWnd, lpszText );

int  GetWindowText( hWnd, lpsBuffer, nMaxCount );

int  GetWindowTextLength( hWnd );

или сообщениями WM_SETTEXT, WM_GETTEXT и WM_GETTEXTLENGTH, которые в случае платформы Win32 позволят получить или изменить текст в окне, принадлежащем другому процессу, в то время как рассмотренные функции могут работать только с окнами, принадлежащими данному процессу.

Однако с большими текстами удобнее работать как с отдельными блоками памяти. Для этого надо будет воспользоваться сообщениями:

EM_GETHANDLE  L

для получения хендла блока, содержащего текст;

EM_SETHANDLE hLocal L

для задания хендла блока, содержащего текст;

EM_LIMITTEXT nMaxChars L

для задания максимального размера текста;

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

Полосы прокрутки

Последний рассматриваемый нами стандартный класс дочерних оконполосы прокрутки, принадлежащие к классу SCROLLBAR. Взаимодействие полос прокрутки с родительским окном отличается от взаимодействия всех остальных стандартных классов.

Вы можете сами создавать полосы прокрутки, но, если вам надо одну-две полосы прокрутки снизу и справа от окна, то проще создать окно со стилями WS_VSCROLL и/или WS_HSCROLL. При этом окно автоматически получит нужные полосы прокрутки. Удобство заключается еще и в том, что эти полосы прокрутки размещаются вне внутренней области окна, то есть Вам не надо учитывать их размер.

Для извещения родительского окна полосы прокрутки посылают сообщения WM_VSCROLL и WM_HSCROLL в зависимости от типа полосы - горизонтальная или вертикальная, а для управления полосами прокрутки используются специальные функции.

Сначала рассмотрим сообщения полосы прокрутки:

WM_VSCROLL ScrollCode wndScroll & nPos
WM_HSCROLL ScrollCode wndScroll
& nPos

в параметре wPar размещается код, указывающий что происходит с полосой прокрутки, старшее слово lPar содержит хендл полосы прокрутки, а младшее слово может указывать на положениедвижкаполосы.

Коды полосы прокрутки могут быть следующие:

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

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

Часто делают так, что родительское окно, обрабатывая сообщения от клавиатуры просто посылает само себе сообщенияот имениполосы прокрутки. Вся обработка прокрутки окна сосредоточена на сообщениях WM_VSCROLL и WM_HSCROLL. В этом случае клавишам Home и End должны соответствовать какие-то коды полосы прокрутки, для чего и добавлены коды SB_TOP и SB_BOTTOM.

Конечно, Вы можете идти иным путем, тогда эти два кода Вам не понадобятся.

Приведем небольшой пример обработки сообщения WM_KEYDOWN родительским окном:

UINT n;

switch ( wMsg ) {

...

case WM_KEYDOWN:

switch ( wPar ) {

case VK_HOME: n= SB_TOP; goto post_vscroll;

case VK_END: n= SB_BOTTOM; goto post_vscroll;

case VK_PRIOR: n= SB_PAGEUP; goto post_vscroll;

case VK_NEXT: n= SB_PAGEDOWN; goto post_vscroll;

case VK_DOWN: n= SB_LINEDOWN; goto post_vscroll;

case VK_UP:  n= SB_LINEUP;

post_vscroll:

 PostMessage( hWnd, WM_VSCROLL, n, 0L );

 break;

default:  break;

}

return 0;

...

}

Далее нас будут интересовать средства для управления полосами прокрутки. Каждая полоса прокрутки характеризуется диапазоном прокрутки, то есть минимальным и максимальным значениями позиции движка. При создании полосы прокрутки ее диапазон устанавливается в 0..100;

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

void GetScrollRange( hWnd, nBar, lpnMin, lpnMax );

int  SetScrollRange( hWnd, nBar, nMin, nMax, bRepaint );

Удобно устанавливать диапазон прокрутки равным, например, числу строк в редактируемом файле.

Некоторых пояснений требуют параметры hWnd и nBar. Параметр hWnd может задавать хендл окна-родителя, тогда с помощью параметра nBar Вы указываете, какая конкретно полоса прокрутки имеется в виду: SB_VERT или SB_HORZ. А если hWnd является хенлом полосы прокрутки, то Вы должны указать nBar равным SB_CTL.

С помощью двух следующих функций Вы можете узнать текущее положение движка полосы или установить его в требуемую позицию.

Int  GetScrollPos( hWnd, nBar );

int  SetScrollPos( hWnd, nBar, nPos, bRepaint );

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

Void ShowScrollBar( hWnd, nBar, bShow );

Окна, рисуемые пользователем

Для некоторых стандартных классов дочерних окон возможно создание окон нестандартного вида. Это так называемые рисуемые пользователем (Owner Draw) окна. Вы можете создавать такие кнопки, и элементы списков (то есть Вы можете наполнять список произвольными объектами, например, рисунками). Тот же способ может быть применен для рисования пунктов меню.

Для того, что бы воспользоваться этой возможностью, Вы должны указать соответсвующий стиль - BS_OWNERDRAW для кнопки, LBS_OWNERDRAWFIXED, LBS_OWNERDRAWVARIABLE, CBS_OWNERDRAWFIXED, CBS_OWNERDRAWVARIABLE для списков. В случае списков различаются два вида рисуемых пользователем элементов - элементы одинаковой высоты (...FIXED) и элементы произвольной высоты (...VARIABLE).

Дочерние окна таких стилей будут посылать своему родительскому окну сообщения WM_MEASUREITEM и WM_DRAWITEM. Обрабатывая эти сообщения родительское окно определяет размеры требуемых элементов и осуществляет их рисование. (Эти же сообщения могут применяться для рисования меню).

WM_MEASUREITEM nID lpMI

это сообщение посылается для определения размеров рисуемого элемента. Параметр wPar содержит идентификатор дочернего окна, а параметр lPar - дальний указатель на структуру MEASUREITEMSTRUCT, которую надо заполнить.

typedef struct tagMEASUREITEMSTRUCT { /* mi */

UINT CtlType; // тип рисуемого элемента

UINT CtlID;  // идентификатор

UINT itemID;  // идентификатор элемента (номер пункта)

UINT itemWidth; // ширина элемента

UINT itemHeight; // высота элемента

DWORD itemData; // данные элемента

} MEASUREITEMSTRUCT;

Поля CtlType, CtlID, itemID и itemData заполняются Windows, вы будете их использоватьь для определения нужного элемента.

Поле CtlType может быть одним из следующих:

ODT_BUTTON  - кнопка

ODT_COMBOBOX - элемент комбинированного список

ODT_LISTBOX  - элемент простого список

ODT_MENU  - элемент меню

Поля CtlID и ItemID определяют идентификаторы дочернего окна и элемента этого дочернего окна (если дочернее окно является списком или рисуется элемент меню).

Поле ItemData является значением, которое Вы передали либо при создании дочернего окна (имя кнопки) либо при добавлении элемента в список или меню (см. сообщения CB_ADDSTRING, CB_INSERTSTRING, LB_ADDSTRING, LB_INSERTSTRING и функции InsertMenu, AddMenu). Обычно это поле является указателем на название окна/элемента.

Два поля itemHeight и itemWidth вы должны определить сами. При этом надо иметь в виду, что некорректное задание этих полей или некорректная обработка сообщения WM_DRAWITEM может привести к непредсказуемым результатам, так как Windows не проверяет корректности значений и выполненых действий).

WM_DRAWITEM nID lpDI

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

typedef struct tagDRAWITEMSTRUCT { /* ditm */

UINT CtlType; // тип рисуемого элемента

UINT CtlID;  // идентификатор

UINT itemID;  // идентификатор элемента (номер пункта)

UINT itemAction; // из-за чего надо рисовать

UINT itemState; // как надо рисовать

HWND hwndItem; // хендл окна рисуемого элемента

HDC  hDC;  // хендл контекста устройства для рисования

RECT rcItem;  // прямоугольник, в котором надо рисовать

DWORD itemData; // данные элемента

} DRAWITEMSTRUCT;

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

Если надо нарисовать элемент, имеющий фокус, то можно оспользоваться функцией

void DrawFocusRect( hDC, lpRect );

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

Управление цветом дочерних окон

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

WM_CTLCOLOR DC CtlType&hwndChild

Параметры этого сообщения следующие:

wPar содержит хендл контекста устройства рисуемого окна младшее слово lPar содержит хендл этого окна, а старшее - тип рисуемого окна:

CTLCOLOR_BTN, CTLCOLOR_DLG, CTLCOLOR_EDIT, CTLCOLOR_LISTBOX, CTLCOLOR_MSGBOX, CTLCOLOR_SCROLLBAR, CTLCOLOR_STATIC

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

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




1. Лекция 13 Патофизиология опухолевого роста Опухоль это патологическое разрастание клеток характер
2. реферату- Основні моменти протоколуРозділ- Діловодство Основні моменти протоколу Протокол ~ це одна з най
3. Экономическая география и регионалистика
4. Типы обсадных колонн
5. тема- обмен энергией и веществом с внешней средой
6. вариантов А что говорить если предложений десятки Как тут не ошибиться выбросив деньги на ветер Ведь игрок
7. Реферат Программа лекционных и практических занятий спецкурса экономическая психология
8. доклад преподавателя по классу фортепиано Ряховской К
9. Проектирование элементов систем электроснабжения сельского хозяйства
10. Философия Утверждены на заседании кафедры 31.
11. Радиотелескопы и космические телескопы
12. I Задачи по неотложным состояниям в акушерстве и гинекологии задача 1 Беременная М
13. А целлобиозе; spergielus niger ~ применяют в производстве для получения-.html
14. великої грецької колонізації- Найдавнішим народом української історії про який збереглися писемні згад
15. когда загрязнение сельхозяйственной продукции и других продуктов питания происходит при выпадении радиоак
16. . Zn 10или решение уря Теорема все решения уря Zn 10 имеют вид k1
17. САНКТПЕТЕРБУРГСКАЯ ЮРИДИЧЕСКАЯ АКАДЕМИЯ РАБОЧАЯ ПРОГРАММА учебной ДИСЦИПЛИНЫ
18. Понятие и признаки административного правонарушения
19. Подготовка и осуществление технологического процесса изготовления деталей сборка изделий автомобиле
20.  Главные формы [3