В этой главе мы расскажем о группе новых органов управления, которые называются общими (generic) органами управления. Это Trackbar , Progressbar , анимационный орган управления Animation , орган циклического просмотра Up-Down и, наконец, орган управления Hot Key .
Все перечисленные выше органы управления просты и удобны.
С помощью органа управления Trackbar пользователь может регулировать какие-либо аналоговые или дискретные параметры, такие как, например, громкость или яркость.
Орган управления Progressbar удобен для отображения процента завершения какого-либо процесса, например, процесса установки программного обеспечения или копирования данных.
Анимационный орган управления Animation предназначен для просмотра видеоклипов (без звукового сопровождения), "оживляющих" приложение.
Ниже в этой главе мы приведем полные исходные тексты приложения Compact Disk Player, демонстрирующих практическое использование трех перечисленных выше органов управления в приложении, предназначенном для проигрывания звуковых компакт-дисков.
Кроме того, в некоторых случаях могут оказаться весьма полезными органы управления Up-Down и Hot Key. Первый из них позволяет организовать циклический просмотр и выбор чисел или текстовых строк, а второй является удобным средством для ввода комбинаций клавиш ускоренного доступа.
В этой главе вы научитесь создавать органы управления Up-Down и Hot Key на примере приложения UpDown, исходные тексты которого приведены в конце книги.
Внешний вид органа управления Trackbar показан на рис. 7.1.
Рис. 7.1. Орган управления Trackbar
По принципу действия и назначению Trackbar напоминает орган управления Scrollbar (полоса просмотра), который мы подробно рассмотрели в 12 томе "Библиотеки системного программиста".
В окне Trackbar имеется движок, который можно перемещать мышью, клавишами перемещения курсора, а также клавишами <Home>, <End>, <PgUp> и <PgDn>. При перемещении движка родительское окно, создавшее орган управления Trackbar, получает извещения. Помимо движка, в окне органа управления Trackbar есть риски (tick marks), разделяющие движок на равные части. Кроме того, можно выделить любой диапазон в окне Trackbar.
Вы можете выбрать горизонтальное или вертикальное расположение органа управления Trackbar. Риски могут находиться с любой стороны, с обеих сторон или их может не быть совсем.
При создании Trackbar приложение должно определить диапазон значений, соответствующих положению движка, шаг расположения рисок, а также шаг изменения этих значений.
Для создания органа управления Trackbar можно
воспользоваться функцией CreateWindowEx , указав ей
предопределенный класс окна TRACKBAR_CLASS . При этом
следует использовать следующие стили,
определяющие расположение и внешний вид органа
управления Trackbar:
Стиль |
Описание |
TBS_HORZ |
Горизонтальное расположение окна Trackbar |
TBS_VERT |
Вертикальное расположение окна Trackbar |
TBS_TOP |
Риски будут расположены сверху
(используется вместе со стилем TBS_HORZ) |
TBS_BOTTOM |
Риски будут расположены снизу
(используется вместе со стилем TBS_HORZ) |
TBS_LEFT |
Риски будут расположены слева
(используется вместе со стилем TBS_VERT) |
TBS_RIGHT |
Риски будут расположены справа
(используется вместе со стилем TBS_VERT) |
TBS_BOTH |
Риски будут расположены с обеих сторон |
TBS_AUTOTICKS |
Если указан этот стиль, риски создаются
для каждого возможного значения из диапазона
значений, определенных для Trackbar |
TBS_NOTICKS |
Сразу после создания окна Trackbar риски не
отображаются, однако позже вы их сможете
определить при помощи сообщений TBM_SETTIC и TBM_SETTICFREQ,
которые будут рассмотрены ниже |
TBS_ENABLESELRANGE |
Возможно выделение диапазона значений |
Не забудьте также инициализировать библиотеку стандартных органов управления, вызвав функцию InitCommonControls :
InitCommonControls();
Чаще всего, однако, орган управления Trackbar создается не функцией CreateWindowEx, а редактором диалоговых панелей. Именно так мы и поступили в приложении Compact Disk Player, просто переместив изображение Trackbar из палитры органов управления в диалоговую панель.
Если для работы вы используете систему Microsoft Visual C++ версии 2.0 , предназначенную для Microsoft Windows NT, то вам потребуется отредактировать регистрационную базу данных (иначе в указанной палитре не будет новых органов управления). Процесс редактирования несложен и описан в SDK.
Прежде всего вам нужно запустить приложение REGEDIT , что можно сделать, например, с помощью всемогущей кнопки Start. На экране появится содержимое регистрационной базы данных в виде дерева просмотра (рис. 7.2).
Рис. 7.2. Просмотр содержимого регистрационной базы данных
Теперь вам нужно раскрыть ветвь этого дерева, которая ведет к набору параметров редактора диалогов. Эта ветвь обозначается как HKEY_CURRENT_USER\Software\Microsoft\Visual C++ 2.0 Dialog Editor.
Далее из меню Edit выберите строки New и Binary Value. Задайте имя для нового элемента данных как ChicagoControls. После этого из меню Edit выберите строку Modify и введите значение 01 00 00 00. Результат показан на рис. 7.3.
Рис. 7.3. Внесенные изменения в регистрационную базу данных, позволяющие использовать новые органы управления в системе разработки Microsoft Visual C++ версии 2.0
Завершите работу редактора регистрационной базы данных. Теперь после перезапуска Microsoft Visual C++ в соответствующей палитре вам будут доступны новые органы управления.
После перемещения изображения органа управления Trackbar в проектируемую диалоговую панель вы можете сделать по этому изображению двойной щелчок левой клавишей мыши и определить стили в блокноте Trackbar Properties (рис. 7.4).
Рис. 7.4. Определение стилей органа управления Trackbar
Когда пользователь перемещает движок органа управления Trackbar, родительское окно получает извещения в форме сообщения WM_HSCROLL (или WM_VSCROLL для горизонтального расположения). Эти извещения аналогичны извещениям, поступающим от полосы просмотра Scrollbar.
Младшее слово параметра wParam сообщения WM_HSCROLL
может содержать один из следующих кодов
извещения:
Код извещения |
Описание |
TB_PAGEUP |
Извещение поступает, когда пользователь
сделал щелчок мышью по полосе Trackbar слева или
сверху от движка, либо нажал клавишу с кодом VK_PRIOR
(клавишу <PgUp>) |
TB_PAGEDOWN |
Пользователь сделал щелчок справа или
снизу от движка, либо нажал клавишу с кодом VK_NEXT
(клавишу <PgDn>) |
TB_LINEUP |
Была нажата клавиша с кодом VK_LEFT или VK_UP
(клавиша перемещения курсора влево или вверх) |
TB_LINEDOWN |
Была нажата клавиша с кодом VK_RIGHT или VK_DOWN
(клавиша перемещения курсора вправо или вниз) |
TB_TOP |
Пользователь нажал клавишу с кодом VK_HOME
(клавишу <Home>) |
TB_BOTTOM |
Пользователь нажал клавишу с кодом VK_END
(клавишу <End>) |
TB_THUMBPOSITION |
Это извещение приходит, когда
пользователь переместил мышью движок в новое
положение |
TB_THUMBTRACK |
Извещение TB_THUMBTRACK приходит в процессе
перемещения движка |
TB_ENDTRACK |
Извещение приходит после завершения
перемещения движка мышью или отпускания клавиши,
с помощью которой перемещался движок |
Ниже мы привели функцию DlgProc_OnHScroll из приложения Compact Disk Player, обрабатывающую извещения от органа управления Trackbar:
void DlgProc_OnHScroll(HWND hdlg, HWND hwndCtl, UINT code, int pos) { switch(code) { case TB_LINEDOWN: case TB_PAGEDOWN: CdPlayNext(hdlg); break; case TB_LINEUP: case TB_PAGEUP: CdPlayPrev(hdlg); break; case TB_BOTTOM: CdPlay(hdlg, nTrackCnt); break; case TB_TOP: CdPlay(hdlg, 1); break; case TB_THUMBPOSITION: CdPlay(hdlg, pos); break; default: break; } }
Как видите, здесь все очень просто.
Функции DlgProc_OnHScroll передаются преобразованные параметры сообщения WM_HSCROLL. Код извещения находится в параметре code, а новое значение позиции (которое нужно для обработки извещения TB_THUMBPOSITION) - в параметре pos.
Ниже мы перечислили сообщения, которые
приложение может посылать органу управления
Trackbar при помощи функции SendMessage :
Сообщение |
Описание |
TBM_CLEARSEL |
Отмена выделения диапазона значений в
окне Trackbar |
TBM_CLEARTICS |
Удаление рисок |
TBM_GETCHANNELRECT |
Определение координат и размеров
воображаемого прямоугольника, ограничивающего
область перемещения движка |
TBM_GETLINESIZE |
Определение величины (в рисках) на
которую перемещается движок, если пользователь
нажимает клавиши с кодами VK_LEFT, VK_RIGHT, VK_UP или VK_DOWN |
TBM_GETNUMTICS |
Определение количества рисок в окне
Trackbar |
TBM_GETPAGESIZE |
Определение величины (в рисках) на
которую перемещается движок, если пользователь
нажимает клавиши с кодами VK_PRIOR или VK_NEXT |
TBM_GETPOS |
Определение текущего положения движка |
TBM_GETPTICS |
Функция SendMessage, посылающая это
сообщение, возвращает указатель на массив
позиций рисок |
TBM_GETRANGEMAX |
Определение максимальной позиции
движка |
TBM_GETRANGEMIN |
Определение минимальной позиции движка |
TBM_GETSELEND |
Определение конечной позиции
выделенной области |
TBM_GETSELSTART |
Определение начальной позиции
выделенной области |
TBM_GETTHUMBLENGTH |
Определение длины движка в пикселах |
TBM_GETTHUMBRECT |
Определение расположения и размеров
движка |
TBM_GETTIC |
Определение позиции риски с заданным
номером |
TBM_GETTICPOS |
Определение физического расположения
указанной риски в системе координат внутренней
области окна |
TBM_SETLINESIZE |
Установка величины (в рисках) на которую
перемещается движок, если пользователь нажимает
клавиши с кодами VK_LEFT, VK_RIGHT, VK_UP или VK_DOWN |
TBM_SETPAGESIZE |
Установка величины (в рисках) на которую
перемещается движок, если пользователь нажимает
клавиши с кодами VK_PRIOR или VK_NEXT |
TBM_SETPOS |
Установка текущего положения движка |
TBM_SETRANGE |
Установка минимальной и максимальной
позиции движка в окне Trackbar |
TBM_SETRANGEMAX |
Установка максимальной позиции движка в
окне Trackbar |
TBM_SETRANGEMIN |
Установка минимальной позиции движка в
окне Trackbar |
TBM_SETSEL |
Установка начальной и конечной позиции
выделенной области |
TBM_SETSELEND |
Установка конечной позиции выделенной
области |
TBM_SETSELSTART |
Установка начальной позиции выделенной
области |
TBM_SETTHUMBLENGTH |
Установка длины движка в пикселах |
TBM_SETTIC |
Установка позиции риски с заданным
номером. Не используется для первой и последней
риски, которые создаются автоматически |
TBM_SETTICFREQ |
Установка интервала, с которым
располагаются риски |
Детальное описание параметров этих сообщений вы найдете в SDK. Из-за недостатка места мы подробно рассмотрим только самые важные из них.
Прежде всего, если оран управления Trackbar расположен в диалоговой панели, вы должны определить его идентификатор. Это можно сделать с помощью функции GetDlgItem (описанной в 12 томе "Библиотеки системного программиста"):
hTrackBar = GetDlgItem(hdlg, IDC_TRACKBAR);
В этом примере в переменную hTrackBar записывается идентификатор окна органа управления Trackbar, который определен в диалоговой панели с идентификатором IDC_TRACKBAR (рис. 7.4).
При инициализации органа управления Trackbar вы должны определить диапазон изменения значений, т. е. минимальную и максимальную позицию движка в окне Trackbar. Это можно сделать с помощью сообщения TBM_SETRANGE :
SendMessage(hTrackBar, TBM_SETRANGE, TRUE, MAKELPARAM(1, nTrackCnt));
Через параметр wParam вместе с этим сообщением передается флаг перерисовки. Если он равен TRUE, сразу после установки диапазона окно органа управления будет перерисовано, если FALSE - нет.
Значение MAKELPARAM(min, max), записанное в lParam, определяет минимальное min и максимальное max значения позиции движка.
Затем нужно установить расстояние, на которое перемещается движок при управлении им с помощью мыши и клавиатуры. Для этого окну органа управления Trackbar нужно послать сообщения TBM_SETPAGESIZE и TBM_SETLINESIZE , например:
SendMessage(hTrackBar, TBM_SETPAGESIZE, 0, 1); SendMessage(hTrackBar, TBM_SETLINESIZE, 0, 1);
Для этих сообщений параметр wParam должен быть равен нулю. В параметр lParam следует записать значение шага.
В данном случае мы устанавливаем одинаковый шаг, однако вы можете использовать и разные шаги. Например, для грубого позиционирования вы можете указать в сообщении TBM_SETPAGESIZE шаг, равный 10, а для тонкого - указать в сообщении TBM_SETLINESIZE шаг, равный 1.
Для принудительной установки движка Trackbar в новую позицию используйте сообщение TBM_SETPOS :
SendMessage(hTrackBar, TBM_SETPOS, TRUE, nCurTrack);
Параметр wParam этого сообщения содержит флаг позиционирования. Если он равен TRUE (как в приведенном выше примере), движок устанавливается в позицию, указанную параметром lParam. Если же этот флаг равен FALSE, движок не перемещается.
Заметьте, что есть одно отличие между полосой просмотра Scrollbar и органом управления Trackbar. Когда пользователь делает щелчок мышью по полосе просмотра, приложение должно в ответ на это установить новое положение движка с помощью функции SetScrollPos . В противоположность этому, в указанной ситуации орган управления Trackbar перемещает движок автоматически.
Орган управления Progressbar ничем не управляет, а служит только для отображения как линейный индикатор (рис. 7.5).
Рис. 7.5. Орган управления Progressbar
Он очень прост в использовании, так как не посылает извещений и воспринимает небольшое количество сообщений.
Так же как и Trackbar, вы можете создать орган управления Progressbar при помощи функции CreateWindowEx , указав ей класс окна PROGRESS_CLASS .
Кроме того, вы можете использовать Progressbar в диалоговых панелях аналогично органу управления Trackbar. Для того чтобы в палитре органов управления редактора диалоговых панелей системы разработки Microsoft Visual C++ версии 2.0 появилась пиктограмма Progressbar, вы должны внести описанные ранее изменения в регистрационную базу данных.
Для органа управления Progressbar при инициализации необходимо задать диапазон изменения значений и начальное значение (в пределах от 0 до 65535).
Для органа управления Progressbar определены пять
сообщений:
Сообщение |
Описание |
PBM_DELTAPOS |
Продвижение заполняющей полосы в окне
индикатора на заданное расстояние, определенное
сообщением PBM_SETSTEP |
PBM_SETPOS |
Установка текущего положения
заполняющей полосы и перерисовка индикатора |
PBM_SETRANGE |
Установка минимальной и максимальной
позиции для органа управления Progressbar |
PBM_SETSTEP |
Установка шага продвижения при
поступлении сообщения PBM_STEPIT (по умолчанию шаг
равен 10) |
PBM_STEPIT |
Продвижение заполняющей полосы в окне
индикатора на величину, определенную сообщением
PBM_SETSTEP |
При инициализации необходимо установить диапазон изменений значений и шаг продвижения.
Первая задача решается с помощью сообщения PBM_SETRANGE:
SendMessage(hProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, nTrackCnt));
Параметр wParam этого сообщения должен быть равен нулю. Значение MAKELPARAM(min, max), записанное в lParam, определяет минимальное min и максимальное max значения позиции для органа управления Progressbar.
Шаг продвижения устанавливается в параметре wParam сообщения PBM_SETSTEP (параметр lParam должен быть равен нулю):
SendMessage(hProgressBar, PBM_SETSTEP, 1, 0);
Если вам нужно установить новое текущее положение заполняющей полосы, это можно сделать при помощи сообщения PBM_SETPOS, указав положение в параметре wParam:
SendMessage(hProgressBar, PBM_SETPOS, nCurTrack, 0);
При этом параметр lParam должен быть равен нулю.
Сообщение PBM_STEPIT не имеет параметров и может быть использовано для продвижения полосы следующим образом:
SendMessage(hProgressBar, PBM_STEPIT, 0, 0);
Если необходимо продвинуть полосу на заданное расстояние, используйте сообщение PBM_DELTAPOS:
SendMessage(hProgressBar, PBM_DELTAPOS, nDelta, 0);
Расстояние должно быть указано в параметре wParam. Параметр lParam должен быть равен нулю.
Орган управления Animation очень прост в использовании и может увеличить привлекательность приложения. На рис. 1.5 в первой главе показано, как с помощью органа управления Animation можно "оживить" процедуру копирования файла. В нашем приложении Compact Disk Player, к которому мы скоро перейдем, этот орган управления используется для изображения вращающегося компакт диска. Диск вращается только тогда, когда выполняется проигрывание дорожки.
Принцип действия органа управления Animation заключается в проигрывании AVI -файла, содержащего видеоизображение. Вы можете создать небольшой мультфильм из отдельных BMP-файлов с помощью приложения VidEdit, которое входит в состав Microsoft Video for Windows 3.1 версии 1.1. Соответствующая процедура описана в 15 томе "Библиотеки системного программиста", который называется "Мультимедиа для Windows".
Учтите, что для сжатия вы можете использовать только алгоритм RLE (можно также использовать несжатые файлы), причем AVI-файл не должен содержать звуковой информации. Если же вам нужно проигрывать видеоклип с звуковым сопровождением, да и еще сжатый более эффективно, лучше всего использовать орган управления MCIWnd , который был подробно описан в 15 томе нашей библиотеки.
Если вы желаете создать орган управления Animation в обычном окне, то это можно сделать с помощью макрокоманды Animate_Create :
HWND Animate_Create( HWND hwndP, // идентификатор родительского окна UINT id, // идентификатор окна органа Animation DWORD dwStyle, // стиль окна органа Animation HINSTANCE hInstance; // идентификатор приложения );
Эта макрокоманда создает орган управления Animation, вызывая функцию CreateWindow и указывая ей предопределенный класс окна ANIMATE_CLASS .
В параметре dwStyle вы можете указать один из
следующих стилей:
Стиль |
Описание |
ACS_AUTOPLAY |
Проигрывание видеоизображения
начинается автоматически сразу после открытия
соответствующего AVI-файла |
ACS_CENTER |
Видеоизображение будет центрировано в
окне органа управления |
ACS_TRANSPARENT |
Изображение рисуется в прозрачном
режиме |
В том случае когда орган управления Animation должен быть расположен в диалоговой панели, его необходимо переместить туда из палитры редактора диалоговых панелей. Если же вы пользуетесь системой разработки Microsoft Visual C++ версии 2.0, вам придется отредактировать файл ресурсов самостоятельно. Для этого откройте его в текстовом режиме и вставьте следующие строки:
CONTROL "Animate",IDC_ANIMATE, "SysAnimate32", WS_BORDER | WS_TABSTOP | 0x1, 219, 34, 33, 33
Последние четыре числа определяют, соответственно расположение и размеры окна органа управления Animation.
Дополнительно к стилям WS_BORDER и WS_TABSTOP могут быть добавлены описанные выше специфические стили органа управления Animation, определенные следующим образом:
#define ACS_CENTER 0x0001 #define ACS_TRANSPARENT 0x0002 #define ACS_AUTOPLAY 0x0004
Для органа управления Animation определены макрокоманды, посылающие сообщения ACM_OPEN, ACM_PLAY и ACM_STOP. Все они возвращают значение TRUE в случае успешного завершения и FALSE при ошибке.
BOOL Animate_Open (hwnd, lpszName);
Через параметр hwnd макрокоманде передается идентификатор органа управления Animation.
Параметр lpszName должен содержать указатель на текстовый буфер, в который записан путь к AVI-файлу или идентификатор ресурса AVI, созданный с помощью макрокоманды MAKEINTRESOURCE.
BOOL Animate_Close (hwnd);
Параметр hwnd должен содержать идентификатор органа управления Animation.
BOOL Animate_Play (hwnd, wFrom, wTo, cRepeat);
Эта макрокоманда запускает проигрывание открытого видеоролика для органа управления Animation с идентификатором hwnd.
Параметры wFrom и wTo указывают, соответственно, номера начального и конечного кадра в видеоролике. Эти номера не должны превышать значения 65536, причем нулевое число означает начало видеоролика.
Параметр cRepeat определяет количество повторных проигрываний, которые необходимо выполнить. Если в этом параметре указано значение -1, проигрывание выполняется бесконечное число раз.
BOOL Animate_Stop (hwnd);
Макрокоманда Animate_Stop выполняет останов запущенного ранее проигрывания видеоролика.
BOOL Animate_Seek (hwnd, wFrame);
С помощью макрокоманды Animate_Seek вы можете отобразить кадр открытого видеоролика с номером wFrame.
Орган управления может посылать в родительское окно извещения в форме сообщения WM_COMMAND . Это извещения ACN_START и ACN_STOP .
Первое из них сообщает о том, что процесс проигрывания видеоролика начался, а второй - что этот процесс завершился.
В качестве примера практического использования органов управления Trackbar, Progressbar и Animation мы предлагаем вам приложение Compact Disk Player, предназначенное для проигрывания дорожек звукового компакт-диска.
Попутно мы продемонстрируем использование MCI-интерфейса в операционной системе Microsoft Windows 95. Напомним, что MCI-интерфейс используется для работы с устройствами мультимедиа. Более подробно вы можете об этом узнать из 15 тома "Библиотеки системного программиста".
Вы также узнаете, как создать приложение Win32, не имеющее главное окно, а представляющее из себя обычную диалоговую панель.
Внешний вид приложения Compact Disk Player показан на рис. 7.6.
Рис. 7.6. Приложение Compact Disk Player
В верхней части окна слева находятся органы управления Trackbar и Progressbar. Первый из них используется для перемещения по дорожкам звукового компакт-диска, второй показывает текущую дорожку. По мере проигрывания дорожек полоса Progressbar и движок Trackbar сдвигаются вправо.
Вы можете переключаться на произвольную дорожку компакт-диска, просто передвигая движок органа Trackbar в нужное место или делая щелчки мышью слева или справа от него в окне Trackbar.
Для перехода к следующей дорожке можно использовать клавишу <PgUp>, клавиши перемещения курсора вверх и вправо, а для перехода к предыдущей - клавишу <PgDn> и клавиши перемещения курсора вниз и влево.
Если нажать на клавишу <Home>, приложение начнет проигрывание с первой дорожки, а если <End> - с последней.
Справа вверху в окне нашего приложения расположен орган управления Animation. Когда проигрывание остановлено, в окне этого органа управления изображается неподвижный компакт-диск. Когда же начинается проигрывание, этот диск начинает вращаться.
В нижней части окна находятся кнопки, с помощью
которых можно управлять процессом проигрывания:
Кнопка |
Назначение |
>> |
Переход к проигрыванию следующей
дорожки |
<< |
Переход к проигрыванию предыдущей
дорожки |
Play |
Запуск проигрывания |
Stop |
Останов проигрывания |
Pause |
Временный останов проигрывания |
Resume |
Продолжение проигрывания после
временного останова |
Eject |
Выталкивание компакт-диска (работает не
на всех типах устройств чтения компакт-диска) |
Exit |
Завершение работы приложения |
При смене компакт-диска количество рисок в окне органа управления Trackbar автоматически устанавливается равным количеству звуковых дорожек.
Еще одно замечание.
Когда вы вставляете музыкальный компакт-диск, операционная система Microsoft Windows 95 автоматически запускает приложение и начинает проигрывание вставленного диска. Для работы с нашим приложением просто остановите проигрывание и завершите приложение CD Player.
Приложение Compact Disk Player сделано на базе приложения MCICDPL, которое было описано в 15 томе "Библиотеки системного программиста".
Функции приложения Compact Disk Player определены в файлах cdplay.c (листинг 7.1) и cdproc.c (листинг 7.2).
Листинг 7.1. Файл cdplay\cdplay.c
#define STRICT #include <windows.h> #include <windowsx.h> #include <commctrl.h> #include "resource.h" #include "afxres.h" #include "cdplay.h" HINSTANCE hInst; char szAppName[] = "CdPlayApp"; char szAppTitle[] = "CD Player"; UINT nTimerID; UINT nCurTrack = 0; UINT nTrackCnt = 0; HWND hwndCurTrack; HWND hProgressBar; HWND hTrackBar; // ----------------------------------------------------- // Функция WinMain // ----------------------------------------------------- int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HWND hWnd; hInst = hInstance; // Преверяем, не было ли это приложение запущено ранее hWnd = FindWindow(szAppName, NULL); if(hWnd) { if(IsIconic(hWnd)) ShowWindow(hWnd, SW_RESTORE); SetForegroundWindow(hWnd); return FALSE; } // Инициализируем библиотеку стандартных органов управления InitCommonControls(); // Отображаем диалоговую панель, которая служит // главным окном приложения DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc); return FALSE; } // ----------------------------------------------------- // Функция DlgProc // ----------------------------------------------------- BOOL APIENTRY DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { HANDLE_MSG(hdlg, WM_INITDIALOG, DlgProc_OnInitDialog); HANDLE_MSG(hdlg, WM_COMMAND, DlgProc_OnCommand); HANDLE_MSG(hdlg, WM_HSCROLL, DlgProc_OnHScroll); HANDLE_MSG(hdlg, WM_TIMER, DlgProc_OnTimer); default: break; } return FALSE; } // ----------------------------------------------------- // Функция DlgProc_OnInitDialog // ----------------------------------------------------- BOOL DlgProc_OnInitDialog(HWND hdlg, HWND hwndFocus, LPARAM lParam) { // Определяем идентификатор поля, которое используется // для отображения номера текущей дорожки hwndCurTrack = GetDlgItem(hdlg, IDT_CURTRACK); // Получаем идентификатор органа Progressbar hProgressBar = GetDlgItem(hdlg, IDC_PROGRESSBAR); // Устанавливаем диапазон изменения значений // и шаг для органа Progressbar SendMessage(hProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, nTrackCnt)); SendMessage(hProgressBar, PBM_SETSTEP, 1, 0); // Получаем идентификатор органа Trackbar hTrackBar = GetDlgItem(hdlg, IDC_TRACKBAR); // Устанавливаем диапазон изменения значений // для органа Trackbar SendMessage(hTrackBar, TBM_SETRANGE, TRUE, MAKELPARAM(1, nTrackCnt)); // Устанавливаем шаг изменений SendMessage(hTrackBar, TBM_SETPAGESIZE, 0, 1); SendMessage(hTrackBar, TBM_SETLINESIZE, 0, 1); // Инициализируем устройство проигрывания // звуковых компакт-дисков CdInit(); // Создаем таймер для периодического определения // состояния устройства проигрывания nTimerID = SetTimer(hdlg, 1, 1000, NULL); // Открываем AVI-файл с видеоклипом (вращающийся // компакт-диск) Animate_Open(GetDlgItem(hdlg, IDC_ANIMATE), "CD.AVI"); return TRUE; } // ----------------------------------------------------- // Функция DlgProc_OnCommand // ----------------------------------------------------- #pragma warning(disable: 4098) void DlgProc_OnCommand(HWND hdlg, int id, HWND hwndCtl, UINT codeNotify) { switch (id) { case IDCANCEL: case IDB_EXIT: { KillTimer(hdlg, nTimerID); // удаляем таймер CdClose(); // закрываем устройство чтения компакт-диска EndDialog(hdlg, TRUE); // завершаем работу приложения break; } // Выполнение команд проигрывания, останова, // паузы, возобновления проигрывания после паузы и т. д. case IDB_PLAY: CdPlay(hdlg, 1); break; case IDB_STOP: CdStop(); break; case IDB_PAUSE: CdPause(); break; case IDB_RESUME: CdResume(hdlg); break; case IDB_NEXT: CdPlayNext(hdlg); break; case IDB_PREV: CdPlayPrev(hdlg); break; case IDB_EJECT: CdEject(); break; default: return FALSE; } return TRUE; } // ----------------------------------------------------- // Функция DlgProc_OnTimer // ----------------------------------------------------- void DlgProc_OnTimer(HWND hwnd, UINT id) { BYTE szBuf[20]; // Если окно свернуто в пиктограмму, ничего не делаем, // чтобы не снижать производительность системы if(IsIconic(hwnd)) return; // Если состояние устройства проигрывания изменилось, // отображаем изменения в диалоговой панели if(CdUpdateState(hwnd)) { // Отображаем номер текущей дорожки if(nCurTrack != 0) { itoa(nCurTrack, szBuf, 10); SetWindowText(hwndCurTrack, szBuf); } else SetWindowText(hwndCurTrack, ""); // Изменяем положение движка Trackbar SendMessage(hTrackBar, TBM_SETPOS, TRUE, nCurTrack); // Изменяем диапазон значений и положение // полосы Progressbar SendMessage(hProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, nTrackCnt)); SendMessage(hProgressBar, PBM_SETPOS, nCurTrack, 0); } } // ----------------------------------------------------- // Функция DlgProc_OnHScroll // ----------------------------------------------------- void DlgProc_OnHScroll(HWND hdlg, HWND hwndCtl, UINT code, int pos) { switch(code) { // Отрабатываем команды, поступающие от органа // управления Trackbar case TB_LINEDOWN: case TB_PAGEDOWN: CdPlayNext(hdlg); break; case TB_LINEUP: case TB_PAGEUP: CdPlayPrev(hdlg); break; case TB_BOTTOM: CdPlay(hdlg, nTrackCnt); break; case TB_TOP: CdPlay(hdlg, 1); break; case TB_THUMBPOSITION: CdPlay(hdlg, pos); break; default: break; } }
В файле cdproc.c (листинг 7.2) собраны функции управления устройством чтения компакт-диска.
Листинг 7.2. Файл cdplay\cdproc.c
#define STRICT #include <windows.h> #include <windowsx.h> #include <commctrl.h> #include "resource.h" #include "afxres.h" #include "cdplay.h" #include <mmsystem.h> DWORD dwrc; MCI_OPEN_PARMS MCIOpen; MCI_SET_PARMS MCISet; MCI_STATUS_PARMS MCIStatus; MCI_PLAY_PARMS MCIPlay; BOOL bMediaPresent = FALSE; BOOL bPaused = FALSE; UINT nMode = 0; HWND hwndCurTrack = NULL; extern UINT nCurTrack; extern UINT nTrackCnt; extern HWND hTrackBar; // ----------------------------------------------------- // Функция CdInit // ----------------------------------------------------- BOOL CdInit(void) { // Открываем устройство чтения компакт-дисков MCIOpen.lpstrDeviceType = (LPSTR)MCI_DEVTYPE_CD_AUDIO; dwrc = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID, (DWORD)&MCIOpen); if(dwrc) { mciwioError(dwrc); return FALSE; } // Устанавливаем формат времени MCISet.dwTimeFormat = MCI_FORMAT_TMSF; dwrc = mciSendCommand(MCIOpen.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)&MCISet); if(dwrc) { mciwioError(dwrc); return FALSE; } return TRUE; } // ----------------------------------------------------- // Функция CdClose // ----------------------------------------------------- void CdClose(void) { // Закрываем устройство чтения компакт-дисков dwrc = mciSendCommand(MCIOpen.wDeviceID, MCI_CLOSE, 0, 0); if(dwrc) mciwioError(dwrc); } //----------------------------------------------------- // mciwioError // Обработка ошибок //----------------------------------------------------- void mciwioError(DWORD dwrc) { BYTE szBuf[MAXERRORLENGTH]; if(mciGetErrorString(dwrc, (LPSTR)szBuf, MAXERRORLENGTH)) MessageBox(NULL, szBuf, "MCIWAVE Error", MB_ICONEXCLAMATION); else MessageBox(NULL, "Неизвестная ошибка", "MCIWAVE Error", MB_ICONEXCLAMATION); } // ----------------------------------------------------- // Функция CdUpdateState // ----------------------------------------------------- BOOL CdUpdateState(HWND hdlg) { BOOL fNeedUpdate = FALSE; UINT nCurMode; // Определяем текущее состояние проигрывателя CD MCIStatus.dwItem = MCI_STATUS_MODE; mciSendCommand(MCIOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD)&MCIStatus); // Проверяем, готово ли устройство чтения к работе if((MCIStatus.dwReturn == MCI_MODE_NOT_READY) || (MCIStatus.dwReturn == MCI_MODE_OPEN)) { // Устройство не готово nCurMode = CD_EMPTY; } else if((MCIStatus.dwReturn == MCI_MODE_STOP) && bPaused) { // Устройство остановлено nCurMode = CD_PAUSED; } else if(MCIStatus.dwReturn == MCI_MODE_PLAY) { // Устройство находится в режиме проигрывания nCurMode = CD_PLAYING; } else { // Устройство готово nCurMode = CD_READY; } // Если с момента последней проверки произошло // изменение режима, записываем код нового режима if(nMode != nCurMode) { fNeedUpdate = TRUE; nMode = nCurMode; // Если устройство находится в режиме проигрывания, // запускаем видеоклип. В противном случае // останавливаем видеоклип в его текущей позиции if(nCurMode == CD_PLAYING) Animate_Play(GetDlgItem(hdlg, IDC_ANIMATE), 0, -1, -1); else Animate_Stop(GetDlgItem(hdlg, IDC_ANIMATE)); } // Проверяем, вставлен ли компакт-диск MCIStatus.dwItem = MCI_STATUS_MEDIA_PRESENT; mciSendCommand(MCIOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD)&MCIStatus); // Если компакт-диск вставлен, определяем // количество звуковых дорожек if((!bMediaPresent) && MCIStatus.dwReturn) { bMediaPresent = TRUE; bPaused = FALSE; nCurTrack = 0; MCIStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; mciSendCommand(MCIOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD)&MCIStatus); nTrackCnt = MCIStatus.dwReturn; // Устанавливаем диапазон изменения значений // для органа управления Trackbar SendMessage(hTrackBar, TBM_SETRANGE, TRUE, MAKELPARAM(1, nTrackCnt)); } // Если компакт-диск не вставлен, сбрасываем // номер текущей дорожки в поле диалоговой панели else if((bMediaPresent) && !MCIStatus.dwReturn) { bMediaPresent = FALSE; bPaused = FALSE; } // Если приложение находится в режиме проигрывания, // определяем номер текущей дорожки if(nCurMode == CD_PLAYING) { // Определяем текущую позицию MCIStatus.dwItem = MCI_STATUS_POSITION; mciSendCommand(MCIOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD)&MCIStatus); // Если номер дорожки изменился, отображаем новое // значение в соответствующем поле диалоговой панели if(nCurTrack != (UINT)MCI_TMSF_TRACK(MCIStatus.dwReturn)) { nCurTrack = (UINT)MCI_TMSF_TRACK(MCIStatus.dwReturn); fNeedUpdate = TRUE; } } return fNeedUpdate; } //----------------------------------------------------- // CdPlay // Запуск проигрывания дорожки //----------------------------------------------------- void CdPlay(HWND hwnd, UINT nTrack) { if(bMediaPresent) { bPaused = FALSE; MCIPlay.dwCallback = (DWORD)hwnd; MCIPlay.dwFrom = MCI_MAKE_TMSF(nTrack, 0, 0, 0); dwrc = mciSendCommand(MCIOpen.wDeviceID, MCI_PLAY, MCI_FROM | MCI_NOTIFY, (DWORD)&MCIPlay); if(dwrc) mciwioError(dwrc); } } //----------------------------------------------------- // CdStop // Останов проигрывания дорожки //----------------------------------------------------- void CdStop(void) { if(bMediaPresent) { bPaused = FALSE; nCurTrack = 0; mciSendCommand(MCIOpen.wDeviceID, MCI_STOP, 0, 0); } } //----------------------------------------------------- // CdPause // Временный останов проигрывания дорожки //----------------------------------------------------- void CdPause(void) { if(bMediaPresent) { if(!bPaused) { bPaused = TRUE; mciSendCommand(MCIOpen.wDeviceID, MCI_PAUSE, 0, 0); } } } //----------------------------------------------------- // CdResume // Возобновление проигрывания после временного останова //----------------------------------------------------- void CdResume(HWND hwnd) { if(bMediaPresent) { if(bPaused) { bPaused = FALSE; MCIPlay.dwCallback = (DWORD)hwnd; mciSendCommand(MCIOpen.wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)&MCIPlay); } } } //----------------------------------------------------- // CdPlayNext // Проигрывание следующей дорожки //----------------------------------------------------- void CdPlayNext(HWND hwnd) { UINT nNewTrack; if(bMediaPresent) { // Если текущая дорожка - последняя, // начинаем проигрывание с первой дорожки. // Если нет - проигрываем следующую дорожку if(nCurTrack == nTrackCnt) nNewTrack = 1; else nNewTrack = nCurTrack + 1; CdPlay(hwnd, nNewTrack); } } //----------------------------------------------------- // CdPlayPrev // Проигрывание предыдущей дорожки //----------------------------------------------------- void CdPlayPrev(HWND hwnd) { UINT nNewTrack; if(bMediaPresent) { // Если текущая дорожка - первая, // проигрываем последнюю дорожку if(nCurTrack <= 1) nNewTrack = nTrackCnt; else nNewTrack = nCurTrack - 1; CdPlay(hwnd, nNewTrack); } } //----------------------------------------------------- // CdEject // Выталкивание компакт-диска //----------------------------------------------------- void CdEject(void) { mciSendCommand(MCIOpen.wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0); }
В файле cdplay.h (листинг 7.3) находятся описания функций, определенных в приложении Compact Disk Player.
Листинг 7.3. Файл cdplay\cdplay.h
BOOL APIENTRY DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam); BOOL DlgProc_OnInitDialog(HWND hdlg, HWND hwndFocus, LPARAM lParam); void DlgProc_OnCommand(HWND hdlg, int id, HWND hwndCtl, UINT codeNotify); void DlgProc_OnTimer(HWND hwnd, UINT id); void DlgProc_OnHScroll(HWND hwnd,HWND hwndCtl,UINT code, int pos); void UpdateDlgControls(void); BOOL CdInit(void); void CdClose(void); void mciwioError(DWORD dwrc); BOOL CdUpdateState(HWND hdlg); void CdPlay(HWND hwnd, UINT nTrack); void CdStop(void); void CdPause(void); void CdResume(HWND hwnd); void CdPlayNext(HWND hwnd); void CdPlayPrev(HWND hwnd); void CdEject(void); #define CD_EMPTY 0 #define CD_READY 1 #define CD_PLAYING 2 #define CD_PAUSED 3
В файле resource.h (создается автоматически системой Microsoft Visual C++) находятся определения констант для работы с ресурсами приложения Compact Disk Player. Этот файл представлен в листинге 7.4.
Листинг 7.4. Файл cdplay\resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by cdplay.rc // #define IDD_DIALOG1 101 #define IDB_NEXT 1000 #define IDB_PREV 1001 #define IDB_PLAY 1002 #define IDB_STOP 1003 #define IDB_PAUSE 1004 #define IDB_RESUME 1005 #define IDB_EJECT 1006 #define IDT_CURTRACK 1008 #define IDB_EXIT 1009 #define IDC_PROGRESSBAR 1012 #define IDC_TRACKBAR 1014 #define IDC_ANIMATE 1015 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_3D_CONTROLS 1 #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1016 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
Файл cdplay.rc (листинг 7.5) содержит определение ресурсов приложения Compact Disk Player.
Листинг 7.5. Файл cdplay\cdplay.rc
//Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ////////////////////////////////////////////////////////////// // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ////////////////////////////////////////////////////////////// // Dialog // IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 278, 138 STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Compact disk player, (C) A. Frolov, 1995" FONT 8, "MS Sans Serif" BEGIN PUSHBUTTON ">>",IDB_NEXT,22,89,50,14 PUSHBUTTON "<<",IDB_PREV,76,89,50,14 PUSHBUTTON "Play",IDB_PLAY,129,89,50,14 PUSHBUTTON "Stop",IDB_STOP,22,106,50,14 PUSHBUTTON "Pause",IDB_PAUSE,76,106,50,14 PUSHBUTTON "Resume",IDB_RESUME,129,106,50,14 PUSHBUTTON "Eject",IDB_EJECT,203,89,50,14 PUSHBUTTON "Exit",IDB_EXIT,203,106,50,14 LTEXT "",IDT_CURTRACK,79,20,92,10 GROUPBOX "",IDC_STATIC,11,6,256,75 CONTROL "Generic1",IDC_PROGRESSBAR, "msctls_progress32", 0x3,25,39,184,9 CONTROL "Generic3",IDC_TRACKBAR, "msctls_trackbar32", WS_TABSTOP | 0x21,19,50,195,25 LTEXT "Track number:",IDC_STATIC,25,20,47,8 GROUPBOX "",IDC_STATIC,11,76,181,53 CONTROL "Animate",IDC_ANIMATE,"SysAnimate32", WS_BORDER | WS_TABSTOP | 0x1,219,34,33,33 GROUPBOX "",IDC_STATIC,191,76,76,53 END #ifdef APSTUDIO_INVOKED ////////////////////////////////////////////////////////////// // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END ////////////////////////////////////////////////////////////// #endif // APSTUDIO_INVOKED #ifndef APSTUDIO_INVOKED ////////////////////////////////////////////////////////////// // Generated from the TEXTINCLUDE 3 resource. ////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
Кратко опишем функции приложения Compact Disk Player, имеющие отношение к органам управления Trackbar, Progressbar и Animation. Особенности использования интерфейса MCI были описаны в 15 томе "Библиотеки системного программиста".
После сохранения идентификатора приложения и проверки на повторный запуск функция WinMain вызывает функцию InitCommonControls, выполняющую инициализацию библиотеки стандартных органов управления.
Далее вызывается функция DialogBox, создающая диалоговую панель. Функция этой диалоговой панели DlgProc выполняет всю полезную работу.
Функция DlgProc обрабатывает сообщения WM_INITDIALOG, WM_COMMAND, WM_HSCROLL и WM_TIMER, вызывая для них, соответственно, функции DlgProc_OnInitDialog, DlgProc_OnCommand, DlgProc_OnHScroll и DlgProc_OnTimer.
Функция DlgProc_OnInitDialog определяет идентификаторы органов управления, расположенных в диалоговой панели, и сохраняет их для дальнейшего использования.
После этого она устанавливает диапазон изменения значений и шаг для органа Progressbar, посылая ему сообщения PBM_SETRANGE и PBM_SETSTEP. В качестве максимального используется значение из переменной nTrackCnt. Как только в устройство чтения компакт-дисков будет вставлен звуковой компакт-диск, обработчик сообщения WM_TIMER запишет в эту переменную количество дорожек.
Шаг изменения значений для органа управления Progressbar устанавливается равным единице.
Затем выполняется инициализация органа управления Trackbar. Максимальное значение устанавливается равным содержимому переменной nTrackCnt (как и для органа Progressbar), а шаг изменения - равным единице. Благодаря этому пользователь сможет перемещаться по всем дорожкам компакт-диска.
После этого обработчик сообщения открывает и инициализирует устройство чтения компакт-дисков, вызывая функцию CdInit, и затем запускает таймер с интервалом, равным примерно одной секунде. Таймер нужен для периодического определения состояния компакт-диска и, в частности, для периодического определения номера текущей дорожки.
На последнем шаге инициализации открывается файл с видеоклипом CD.AVI, который должен находится в текущем каталоге. Этот файл открывается макрокомандой Animate_Open.
Функция DlgProc1_OnCommand обрабатывает сообщение WM_COMMAND, поступающее от органов управления диалоговой панели.
Когда пользователь нажимает кнопку Exit или клавишу <Esc> обработчик уничтожает таймер, закрывает устройство чтения компакт-диска при помощи функции CdClose и затем закрывает диалоговую панель, вызывая функцию EndDialog. В результате приложение завершает свою работу.
Обработка остальных кнопок выполняется соответствующими функциями, определенными в файле cdproc.c (листинг 7.2). Действия, которые выполняют эти функции, были описаны нами в 15 томе "Библиотеки системного программиста", поэтому для экономии места мы не будем рассказывать о них еще раз.
Функция DlgProc_OnTimer обрабатывает сообщение WM_TIMER , поступающее примерно один раз в секунду. Если диалоговая панель находится в минимизированном состоянии (что определяется с помощью функции IsIconic), обработчик сразу возвращает управление.
В противном случае вызывается функция CdUpdateState, определяющая текущее состояние устройства чтения компакт-дисков и выполняющая некоторые другие действия, связанные с обновлением состояния органов управления диалоговой панели.
Если в результате вызова этой функции выяснилось, что состояние изменилось, функция DlgProc_OnTimer отображает номер текущей дорожки в статическом органе управления с идентификатором hwndCurTrack. После этого она изменяет положение движка Trackbar, чтобы он указывал на текущую дорожку, а также устанавливает диапазон значений и новое положение полосы Progressbar.
Функция DlgProc_OnHScroll обрабатывает сообщение WM_HSCROLL , которое вырабатывает орган управления Trackbar.
В ответ на извещения TB_LINEDOWN и TB_PAGEDOWN обработчик вызывает функцию CdPlayNext, которая проигрывает следующую дорожку. При обработке извещений TB_LINEUP и TB_PAGEUP вызывается функция CdPlayPrev, которая проигрывает предыдущую дорожку.
Когда пользователь нажимает клавиши <Home> или <End>, обработчики извещений TB_TOP и TB_BOTTOM запускают проигрывание, соответственно, первой и последней дорожки звукового компакт-диска.
Если пользователь перемещает движок органа управления Trackbar в новое положение, обработчик извещения TB_THUMBPOSITION запускает проигрывание той дорожки, которая была выбрана и номер которой был передан вместе с этим извещением.
В этом разделе мы расскажем вам об очень простом органе управления Up-Down , который мы будем называть органом циклического просмотра.
|
Внешне этот орган управления похож на
вырожденную полосу просмотра Scrollbar, у которой нет
движка, а верхняя и нижняя кнопка расположены
рядом. |
Вы можете создать вертикальный или горизонтальный орган циклического просмотра, просто указав соответствующий стиль окна органа Up-Down.
Обычно орган управления Up-Down используется для изменения значения какого-либо параметра (например, количества копий при печати). При этом он комбинируется с однострочным текстовым редактором, как это показано на рис. 7.7.
Рис. 7.7. Комбинирование органа управления Up-Down и однострочного текстового редактора
В этом случае можно сделать так, что когда пользователь нажимает кнопки органа управления Up-Down, в окне текстового редактора появляются значения, которые находятся в заранее заданном диапазоне. Пользователь может также ввести нужное значение непосредственно в окне текстового редактора.
Вы также можете объединить орган циклического просмотра с другим органом управления, например, с органом управления Tab или Trackbar. Способ такого объединения органов управления будет описан ниже.
Орган управления Up-Down создается функцией CreateWindowEx на базе предопределенного класса окна UPDOWN_CLASS . При этом следует сохранить полученный от функции CreateWindowEx идентификатор для посылки окну органа Up-Down управляющих сообщений.
Вы можете также переместить изображение пиктограммы органа Up-Down из палитры редактора диалогов в проектируемую диалоговую панель. Если вы работаете с системой Microsoft Visual C++ версии 2.0 , не забудьте внести изменения в регистрационную базу данных, описанные в этой главе.
Для определения идентификатора окна органа управления Up-Down, расположенного в диалоговой панели, вы можете воспользоваться функцией GetDlgItem .
Есть еще один способ, который удобен при объединении органа Up-Down с каким-либо другим органом управления. Этот способ основан на использовании функции CreateUpDownControl :
HWND CreateUpDownControl( DWORD dwStyle, // стиль окна органа Up-Down int x, // расположение окна int y, int cx, // размеры окна int cy, HWND hParent, // иднтификатор родительского окна int nID, // идентификатор органа Up-Down HINSTANCE hInst, // идентифкатор приложения HWND hBuddy, // идентификатор сцепленного органа int nUpper, // верхняя граница значений int nLower, // нижняя граница значений int nPos); // начальное значение
Функция CreateUpDownControl выполняет несколько действий.
Прежде всего, она создает орган управления Up-Down с помощью функции CreateWindowEx на базе предопределенного класса окна UPDOWN_CLASS . Затем она устанавливает диапазон возможных значений и начальное значение, посылая окну органа управляющие сообщения. Затем функция CreateUpDownControl подключает орган Up-Down к органу управления с идентификатором hBuddy.
Остановимся подробнее на объединении органов управления .
Окно органа управления, с которым сцепляется орган Up-Down, называется сцепленным окном (buddy window ). Так как при сцеплении органы действуют как единое целое и находятся внутри одной рамки (рис. 7.7), пользователю кажется, что он работает с одним органом управления.
Вы можете сцепить окна органов управления двумя различными способами.
Во-первых, для органа управления Up-Down можно задать стиль окна UDS_AUTOBUDDY . При этом последний сцепляется с органом управления, расположенным под ним (с предыдущим по порядку в шаблоне диалоговой панели).
Во-вторых, вы можете сцепить органы управления, послав окну органа Up-Down сообщение UDM_SETBUDDY . Именно этот способ и используется функцией CreateUpDownControl.
При создании органа Up-Down вы должны указывать
обычные стили окна, такие как WS_CHILD , WS_BORDER и WS_VISIBLE ,
а также дополнительные, определяющие поведение
этого органа управления:
Стиль |
Описание |
UDS_ALIGNLEFT |
Орган Up-Down будет выровнен по левой
границе окна сцепленного с ним органа управления
|
UDS_ALIGNRIGHT |
То же, но по правой границе |
UDS_SETBUDDYINT |
В заголовок окна органа управления,
сцепленного с органом Up-Down, будет автоматически
записываться текущее значение, установленное
для органа Up-Down. Если же орган Up-Down сцеплен с
органом Listbox, заголовок изменяться не будет.
Вместо этого будет изменяться номер выделенного
элемента списка |
UDS_NOTHOUSANDS |
Используется вместе со стилем UDS_SETBUDDYINT.
Указывает, что при отображении текущего значения
не нужно разделять разряды тысяч десятичной
точкой |
UDS_ARROWKEYS |
Если указан этот стиль, для изменения
текущего значения можно использовать клавиши
перемещения курсора по вертикали |
UDS_HORZ |
Размещение окна органа Up-Down по
горизонтали |
UDS_WRAP |
При достижении в процессе перебора
значений верхней или нижней границы будет
происходить переход, соответственно, к нижнему
или верхнему значению. Таким образом, возможна
организация циклического перебора возможных
значений |
Вот пример создания органа Up-Down, сцепленного с однострочным текстовым редактором hwndEdit, который расположен в диалоговой панели:
hwndUpDown = CreateUpDownControl ( WS_CHILD | WS_BORDER | WS_VISIBLE | UDS_WRAP | UDS_ARROWKEYS | UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0, hdlg, IDC_UPDOWN, hInst, hwndEdit,10, 1, 1);
Обратите внимание, что мы не указали размеры и расположение окна органа Up-Down, так как при сцеплении они устанавливаются автоматически.
Для органа управления Up-Down определены
следующие сообщения:
Сообщение |
Описание |
UDM_GETACCEL |
Получение параметров режима ускорения
работы органа управления Up-Down |
UDM_GETBASE |
С помощью этого сообщения приложение
может определить, какая система счисления
(десятичная или шестнадцатиричная) используется
для органа Up-Down |
UDM_GETBUDDY |
Определение идентификатора окна органа
управления, сцепленного с органом Up-Down |
UDM_GETPOS |
Определение текущего значения |
UDM_GETRANGE |
Определение интервала значений |
UDM_SETACCEL |
Установка параметров режима ускорения
работы органа управления Up-Down |
UDM_SETBASE |
Установка десятичной или
шестнадцатиричной системы счисления |
UDM_SETBUDDY |
Подключение сцепленного органа
управления |
UDM_SETPOS |
Установка текущего значения |
UDM_SETRANGE |
Установка интервала значений |
Сообщение UDM_SETACCEL позволяет установить режим ускорения. В этот режим орган управления Up-Down переходит в том случае, если пользователь держит одну из кнопок органа нажатой в течении определенного интервала времени. После этого текущее значение, связанное с органом Up-Down, начинает изменяться автоматически. Подробности вы можете найти в справочной системе SDK.
Для подключения органа Up-Down к окну другого органа управления вам может пригодиться сообщение UDM_SETBUDDY. Параметр wParam этого сообщения должен содержать идентификатор окна органа управления, к которому будет выполняться подключение.
С помощью сообщения UDM_SETRANGE вы можете установить диапазон значений (такая операция может вам пригодиться при инициализации органа Up-Down, созданного функцией CreateWindowEx). Параметр wParam этого сообщения должен быть равен нулю, а параметр lParam необходимо указать следующим образом:
lParam = (LPARAM) MAKELONG((short)nMax, (short)nMin);
Здесь nMin и nMax задают, соответственно, нижний и верхний предел изменения значения. Параметр nMin не должен быть меньше константы UD_MINVAL, а параметр nMax - больше константы UD_MAXVAL. Кроме того, минимальное и максимальное значение не должны отличаться друг от друга больше чем на значение константы UD_MAXVAL.
С помощью сообщения UDM_SETPOS можно задать текущее значение. При этом в параметр wParam нужно записать ноль, а параметр lParam подготовить так:
lParam = (LPARAM) MAKELONG((short)nPos, 0);
Параметр nPos должен содержать новое значение.
При установке системы счисления вы должны в параметр wParam сообщения UDM_SETBASE записать значение 10 (для десятичной системы счисления) или 16 (для шестнадцатиричной). В параметр lParam нужно записать нулевое значение.
Когда позиция органа управления Up-Down (т. е. текущее значение, связанное с органом) изменяется, родительское окно получает извещение UDN_DELTAPOS , которое поступает в форме сообщения WM_NOTIFY .
При этом в параметре lParam передается адрес структуры NM_UPDOWN , содержащей информацию об изменении:
typedef struct _NM_UPDOWN { NMHDR hdr; // заголовок извещения int iPos; // текущая позиция int iDelta; // предполагаемая величина изменения позиции } NM_UPDOWNW;
Обработчик этого извещения может разрешить или запретить изменение позиции, возвратив, соответственно, значение TRUE или FALSE. Кроме того, обработчик извещения может при необходимости изменить содержимое поля iDelta.
Последний орган управления, который мы рассмотрим в этой книге, предназначен для ввода комбинации клавиш активизации приложения. Однако прежде мы должны немного рассказать о том, что это такое.
Пользователь может определить комбинацию клавиш для быстрого доступа к какой-либо часто выполняемой операции. Такую комбинацию клавиш мы будем называть комбинацией клавиш активизации или просто клавишами активизации .
В операционной системе Microsoft Windows 95 вы можете установить так называемую глобальную комбинацию клавиш для активизации при помощи сообщения WM_SETHOTKEY , послав его главному окну приложения. Заметим, что сообщение WM_SETHOTKEY не имеет никакого отношения к органу управления Hot Key .
Параметр lParam этого сообщения должен быть равен нулю. Клавиши активизации задаются параметром lParam следующим образом:
wParam = (WPARAM)MAKEWORD (vkey, modifiers);
Здесь vkey определяет виртуальный код клавиши. Список виртуальных кодов для различных клавиш вы найдете в пятой главе 12 тома "Библиотеки системного программиста" (стр. 158).
Параметр modifiers определяет клавиши модификации,
такие как <Ctrl> и <Alt>, которые нужно нажимать
вместе с клавишей, заданной параметром vkey для
активизации. Параметр modifiers нужно задавать как
комбинацию следующих значений:
Значение |
Клавиша модификации |
HOTKEYF_ALT |
<Alt> |
HOTKEYF_CONTROL |
<Ctrl> |
HOTKEYF_EXT |
Дополнительные клавиши, такие как
правая клавиша <Ctrl> или правая клавиша <Alt>.
Дополнительные клавиши есть не на всех
клавиатурах |
HOTKEYF_SHIFT |
<Shift> |
Ниже мы показали, как задать комбинацию <Ctrl+Alt+V> в качестве клавиш активизации:
SendMessage(hWnd, WM_SETHOTKEY, (WPARAM)MAKEWORD('V', HOTKEYF_ALT | HOTKEYF_CONTROL), 0);
Что же произойдет, когда пользователь нажмет клавиши активизации, заданные таким образом?
Главное окно приложение будет выдвинуто на первый план, а его функция получит сообщение WM_SYSCOMMAND с кодом команды SC_HOTKEY . При этом обработчик сообщения WM_SYSCOMMAND может выполнить какие-либо действия, например, послать главному окну приложения другое сообщение.
Ниже мы привели исходный текст обработчика сообщения WM_SYSCOMMAND из приложения UpDown:
void WndProc_OnSysCommand(HWND hwnd, UINT cmd, int x, int y) { if(cmd == SC_HOTKEY) { SendMessage(hwndMainWindow, WM_COMMAND, (WPARAM)MAKELONG(ID_FILE_OPTIONS, 0), 0L); return 0; } return FORWARD_WM_SYSCOMMAND (hwnd,cmd,x,y,DefWindowProc); }
Здесь обработчик посылает главному окну сообщение WM_COMMAND, имитируя выбор из меню File строки Options.
С помощью сообщения WM_SETHOTKEY пользователь может назначить для приложения только одну комбинацию клавиш активизации.
Приложение может определить, была ли назначена окну комбинация клавиш активизации и если была, то какая именно. Для этого достаточно послать окну сообщение WM_GETHOTKEY , например, так:
wHotKey = (WORD)SendMessage(hwndMainWindow,WM_GETHOTKEY,0,0);
Если комбинация клавиш активизации не была назначена, возвращается значение NULL, а если была, то возвращается значение, которое можно использовать в качестве параметра wParam сообщения WM_SETHOTKEY.
Итак, для того чтобы определить комбинацию клавиш активизации, можно воспользоваться сообщением WM_SETHOTKEY. Что же касается подготовки значения wParam для этого сообщения, то это можно сделать с помощью органа управления Hot Key, к описанию которого мы и перейдем.
Внешне орган управления Hot Key похож на однострочный текстовый редактор (рис. 7.8).
Рис. 7.8. Окно органа управления Hot Key
Когда это окно получает фокус ввода, пользователь может нажимать комбинацию клавиш активизации, которая тотчас же будет в нем отображаться. Таким образом, пользователь сразу видит, какая комбинация клавиш выбрана.
Послав окну органа управления Hot Key сообщение HKM_GETHOTKEY , приложение может определить выбранную комбинацию клавиш и передать значение, возвращенное функцией SendMessage как параметр wParam сообщению WM_SETHOTKEY.
Этот нехитрый механизм позволяет легко организовать процедуру определения пользователем комбинации клавиш активизации.
Вы можете создать орган управления Hot Key функцией CreateWindowEx на базе предопределенного класса окна HOTKEY_CLASS , либо добавить его к диалоговой панели, выбрав соответствующую пиктограмму из палитры редактора диалога. Например:
hwndHotKey = CreateWindowEx( 0, HOTKEY_CLASS, "", WS_CHILD | WS_VISIBLE, 30, 50, 100, 32, hWnd, NULL, hInst, NULL);
В приложении UpDown мы выбрали второй способ.
Инициализацию органа управления Hot Key выполняют с помощью сообщения HKM_SETHOTKEY . Параметр lParam должен быть равен нулю, а параметр wParam следует определить следующим образом:
wParam = MAKEWORD (vkey, modifiers);
Параметры vkey и modifiers имеют то же назначение, что и в сообщении WM_SETHOTKEY.
Кроме этого, при инициализации с помощью сообщения HKM_SETRULES можно указать запрещенные комбинации клавиш и клавиши, которые используются по умолчанию.
Параметры сообщения HKM_SETRULES приведены ниже:
wParam = (WPARAM) fwInvalid; lParam = MAKELPARAM (modifiers, 0);
Параметр fwInvalid указывает запрещенные клавиши и
может быть комбинацией следующих значений:
Значение |
Запрещенные клавиши |
HKCOMB_A |
<Alt> |
HKCOMB_C |
<Ctrl> |
HKCOMB_CA |
<Ctrl + Alt> |
HKCOMB_NONE |
Запрещается использовать клавиши без
модификаторов, т. е. без клавиш <Alt>, <Ctrl> или
<Shift> |
HKCOMB_S |
<Shift> |
HKCOMB_SA |
<Shift + Alt> |
HKCOMB_SC |
<Shift + Ctrl> |
HKCOMB_SCA |
<Shift + Ctrl + Alt> |
Когда пользователь пытается определить запрещенную комбинацию клавиш, вместо нее будет выбрана та, что указана параметром modifiers.
Несложное приложение UpDown демонстрирует, как это нетрудно догадаться из его названия, работу органа управления Up-Down. Дополнительно в этом приложении мы создаем комбинацию клавиш активизации, работаем с сообщением WM_SETHOTKEY и органом управления Hot Key.
Если выбрать строку Options из главного меню приложения File, на экране появится диалоговая панель Value Selection, показанная на рис. 7.9.
Рис. 7.9. Диалоговая панель Value Selection
В этой панели вы можете задать с помощью органа управления Up-Down некоторое значение, и посмотреть результат, нажав кнопку OK.
В процессе инициализации своего главного окна приложение определяет комбинацию клавиш активизации <Ctrl + Alt + V>. Если нажать эту комбинацию клавиш, появится все та же диалоговая панель.
Для изменения комбинации клавиш активизации вы можете передать фокус ввода органу управления Hot Key, нажать новую комбинацию клавиш и затем нажать кнопку Set HotKey. После этого новая комбинация клавиш может быть использована для активизации диалоговой панели Value Selection.
Исходные тексты всех функций приложения UpDown собраны в файле updown.c (листинг 7.6).
Листинг 7.6. Файл updown\updown.c
#define STRICT #include <windows.h> #include <windowsx.h> #include <commctrl.h> #include "resource.h" #include "afxres.h" #include "updown.h" HINSTANCE hInst; char szAppName[] = "UpDownApp"; char szAppTitle[] = "Up-Down and HotKey Demo"; HWND hwndEdit; HWND hwndUpDown; HWND hwndMainWindow; HWND hwndHotKey; WORD wHotKey; // ----------------------------------------------------- // Функция WinMain // ----------------------------------------------------- int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; HWND hWnd; MSG msg; hInst = hInstance; // Преверяем, не было ли это приложение запущено ранее hWnd = FindWindow(szAppName, NULL); if(hWnd) { if(IsIconic(hWnd)) ShowWindow(hWnd, SW_RESTORE); SetForegroundWindow(hWnd); return FALSE; } // Регистрируем класс окна memset(&wc, 0, sizeof(wc)); wc.cbSize = sizeof(WNDCLASSEX); wc.hIconSm = LoadImage(hInst, MAKEINTRESOURCE(IDI_APPICONSM), IMAGE_ICON, 16, 16, 0); wc.style = 0; wc.lpfnWndProc = (WNDPROC)WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; wc.hIcon = LoadImage(hInst, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 32, 32, 0); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wc.lpszMenuName = MAKEINTRESOURCE(IDR_APPMENU); wc.lpszClassName = szAppName; if(!RegisterClassEx(&wc)) if(!RegisterClass((LPWNDCLASS)&wc.style)) return FALSE; // Создаем главное окно приложения hWnd = CreateWindow(szAppName, szAppTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL); if(!hWnd) return(FALSE); // Сохраняем идентификатор главного окна hwndMainWindow = hWnd; // Отображаем окно и запускаем цикл обработки сообщений ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); while(GetMessage (&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } // ----------------------------------------------------- // Функция WndProc // ----------------------------------------------------- LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { HANDLE_MSG(hWnd, WM_CREATE, WndProc_OnCreate); HANDLE_MSG(hWnd, WM_DESTROY, WndProc_OnDestroy); HANDLE_MSG(hWnd, WM_COMMAND, WndProc_OnCommand); HANDLE_MSG(hWnd, WM_SYSCOMMAND, WndProc_OnSysCommand); default: return(DefWindowProc(hWnd, msg, wParam, lParam)); } } // ----------------------------------------------------- // Функция WndProc_OnCreate // ----------------------------------------------------- BOOL WndProc_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct) { // Инициализируем библиотеку стандартных органов управления InitCommonControls(); // Устанавливаем комбинацию клавиш активизации // диалоговой панели <Alt+Ctrl+V> SendMessage(hWnd, WM_SETHOTKEY, (WPARAM)MAKEWORD('V', HOTKEYF_ALT | HOTKEYF_CONTROL), 0); return TRUE; } // ----------------------------------------------------- // Функция WndProc_OnDestroy // ----------------------------------------------------- #pragma warning(disable: 4098) void WndProc_OnDestroy(HWND hWnd) { PostQuitMessage(0); return 0L; } // ----------------------------------------------------- // Функция WndProc_OnCommand // ----------------------------------------------------- #pragma warning(disable: 4098) void WndProc_OnCommand(HWND hWnd, int id, HWND hwndCtl, UINT codeNotify) { switch (id) { case ID_FILE_EXIT: PostQuitMessage(0); // завершаем работу приложения return 0L; break; case ID_HELP_ABOUT: MessageBox(hWnd, "Up-Down and HotKey Demo Application, v.1.0\n" "(C) Alexandr Frolov, 1995\n" "Email: frolov@glas.apc.org", szAppTitle, MB_OK | MB_ICONINFORMATION); return 0L; break; case ID_FILE_OPTIONS: { DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc); return 0L; break; } default: break; } return FORWARD_WM_COMMAND(hWnd, id, hwndCtl, codeNotify, DefWindowProc); } // ----------------------------------------------------- // Функция DlgProc // ----------------------------------------------------- BOOL APIENTRY DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { HANDLE_MSG(hdlg, WM_INITDIALOG, DlgProc_OnInitDialog); HANDLE_MSG(hdlg, WM_COMMAND, DlgProc_OnCommand); default: break; } return FALSE; } // ----------------------------------------------------- // Функция DlgProc_OnInitDialog // Вызывается при инициализации первой страницы // ----------------------------------------------------- BOOL DlgProc_OnInitDialog(HWND hdlg, HWND hwndFocus, LPARAM lParam) { // Получаем идентификатор редактора текста hwndEdit = GetDlgItem(hdlg, IDC_EDIT1); // Создаем орган управления Up-Down и подключаем // его к редактору текста. Задаем начальное // и конечное значение, инициализируем // редактор текста hwndUpDown = CreateUpDownControl( WS_CHILD | WS_BORDER | WS_VISIBLE | UDS_WRAP | UDS_ARROWKEYS | UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0, hdlg, IDC_UPDOWN, hInst, hwndEdit,10, 1, 1); // Получаем идентификатор органа Hot Key hwndHotKey = GetDlgItem(hdlg, IDC_HOTKEY); // Получаем код комбинации клавиш, которая // используется для активизации диалоговой панели wHotKey = (WORD)SendMessage(hwndMainWindow, WM_GETHOTKEY, 0, 0); // Устанавливаем начальное состояние органа Hot Key // в соответствии с полученным кодом if(wHotKey != 0) SendMessage(hwndHotKey, HKM_SETHOTKEY, wHotKey, 0); return TRUE; } // ----------------------------------------------------- // Функция DlgProc_OnCommand // ----------------------------------------------------- #pragma warning(disable: 4098) void DlgProc_OnCommand(HWND hdlg, int id, HWND hwndCtl, UINT codeNotify) { int nValue; char szBuf[80]; BOOL fError; switch (id) { case IDOK: { // Определяем и отображаем выбранное значение nValue = (int)GetDlgItemInt(hdlg, IDC_EDIT1, &fError, FALSE); wsprintf(szBuf, "Value:\t%d", nValue); MessageBox(NULL, szBuf, szAppTitle, MB_OK | MB_ICONINFORMATION); EndDialog(hdlg, TRUE); break; } case IDC_SETHOTKEYBUTTON: { // Получаем код комбинации клавиш, которая // используется для активизации диалоговой панели wHotKey = (WORD)SendMessage(hwndHotKey, HKM_GETHOTKEY, 0, 0); // Устанавливаем новую комбинацию клавиш для // активизации диалоговой панели SendMessage(hwndMainWindow, WM_SETHOTKEY, wHotKey, 0); break; } case IDCANCEL: { EndDialog(hdlg, TRUE); break; } default: return FALSE; } return TRUE; } // ----------------------------------------------------- // Функция WndProc_OnSysCommand // ----------------------------------------------------- #pragma warning(disable: 4098) void WndProc_OnSysCommand(HWND hwnd, UINT cmd, int x, int y) { // Если пришло сообщение от клавиши активизации, // посылаем функции главного окна сообщение WM_COMMAND // с кодом, соответствующем строке Options меню File // для активизации диалоговой панели if(cmd == SC_HOTKEY) { SendMessage(hwndMainWindow, WM_COMMAND, (WPARAM)MAKELONG(ID_FILE_OPTIONS, 0), 0L); return 0; } return FORWARD_WM_SYSCOMMAND(hwnd, cmd, x, y, DefWindowProc); }
Описания функция и идентификатор IDC_UPDOWN органа управления Up-Down находятся в файле updown.h (листинг 7.7).
Листинг 7.7 Файл updown\updown.h
// ----------------------------------------------------- // Описание функций // ----------------------------------------------------- LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); BOOL WndProc_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct); void WndProc_OnDestroy(HWND hWnd); void WndProc_OnCommand(HWND hWnd, int id, HWND hwndCtl, UINT codeNotify); BOOL APIENTRY DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam); BOOL DlgProc_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam); void DlgProc_OnCommand(HWND hWnd, int id, HWND hwndCtl, UINT codeNotify); void WndProc_OnSysCommand(HWND hwnd, UINT cmd, int x, int y); #define IDC_UPDOWN 1224
В файле resource.h (листинг 7.8), созданном автоматически, определены константы идентификаторов ресурсов приложения.
Листинг 7.8 Файл updown\resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by UPDOWN.RC // #define IDR_APPMENU 102 #define IDI_APPICON 103 #define IDI_APPICONSM 104 #define IDD_DIALOG1 121 #define IDC_EDIT1 1009 #define IDC_HOTKEY 1010 #define IDC_SETHOTKEYBUTTON 1011 #define ID_FILE_EXIT 40001 #define ID_HELP_ABOUT 40003 #define ID_FILE_OPTIONS 40029 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 126 #define _APS_NEXT_COMMAND_VALUE 40030 #define _APS_NEXT_CONTROL_VALUE 1012 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
Файл updown.rc (листинг 7.9) содрежит определения ресурсов приложения.
Листинг 7.9 Файл updown\updown.rc
//Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ////////////////////////////////////////////////////////////// // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ////////////////////////////////////////////////////////////// // Menu // IDR_APPMENU MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "&Options...", ID_FILE_OPTIONS MENUITEM SEPARATOR MENUITEM "E&xit", ID_FILE_EXIT END POPUP "&Help" BEGIN MENUITEM "&About...", ID_HELP_ABOUT END END #ifdef APSTUDIO_INVOKED ////////////////////////////////////////////////////////////// // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END ////////////////////////////////////////////////////////////// #endif // APSTUDIO_INVOKED ////////////////////////////////////////////////////////////// // Icon // IDI_APPICON ICON DISCARDABLE "updown.ico" IDI_APPICONSM ICON DISCARDABLE "updownsm.ico" ////////////////////////////////////////////////////////////// // Dialog // IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 194, 95 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Value selection" FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_EDIT1,15,9,40,13,ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,130,6,50,14 PUSHBUTTON "Cancel",IDCANCEL,130,23,50,14 CONTROL "Generic1",IDC_HOTKEY,"msctls_hotkey32",WS_TABSTOP,13,66, 80,12 PUSHBUTTON "Set HotKey",IDC_SETHOTKEYBUTTON,130,65,50,14 GROUPBOX "Hot Key",IDC_STATIC,8,49,178,40 END ////////////////////////////////////////////////////////////// // String Table // STRINGTABLE DISCARDABLE BEGIN ID_FILE_EXIT "Quits the application" END #ifndef APSTUDIO_INVOKED ////////////////////////////////////////////////////////////// // Generated from the TEXTINCLUDE 3 resource. ////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
Расскажем о наиболее важных функциях, определенных в приложении Up-Down.
Функция WndProc_OnCreate обрабатывает сообщение WM_CREATE , поступающее в функцию главного окна приложения при его инициализации.
После инициализации библиотеки стандартных органов управления функция WndProc_OnCreate определяет комбинацию клавиш <Alt+Ctrl+V> как комбинацию клавиш активизации диалоговой панели Value Selection (рис. 7.9). Для этого главному окну приложения посылается сообщение WM_SETHOTKEY .
Функция WndProc_OnCommand содержит обработчик сообщения WM_COMMAND , поступающего от главного меню приложения, а также в том случае, если пользователь нажимает комбинацию клавиш активизации диалоговой панели Value Selection.
Если вместе с этим сообщением приходит код команды ID_FILE_OPTIONS, с помощью функции DialogBox создается указанная выше диалоговая панель.
Функция DlgProc_OnInitDialog вызывается при инициализации диалоговой панели Value Selection, когда в окно этой диалоговой панели приходит сообщение WM_INITDIALOG .
При этом вначале соответствующий обработчик получает идентификатор окна редактора текста, к которому будет привязан орган управления Up-Down, и сохраняет его в переменной hwndEdit.
Затем с помощью функции CreateUpDownControl создается орган управления Up-Down. Функция CreateUpDownControl привязывает созданный орган управления к редактору текста hwndEdit и выполняет все необходимые инициализирующие действия.
Далее функции главного окна приложения посылается сообщение WM_GETHOTKEY . Если для приложения определена комбинация клавиш активизации, то эта комбинация используется для инициализации органа управления Hot Key, расположенного в диалоговой панели Value Selection.
Эта функция обрабатывает сообщение WM_COMMAND , поступающее в функцию окна диалоговой панели Value Selection от органов управления, расположенных в этой диалоговой панели.
Если пользователь нажимает кнопку OK, обработчик получает целое значение, соответствующее текстовой строке из редактора IDC_EDIT1. Так как последний был привязан к органу управления Up-Down, полученное значение соответствует текущему для органа Up-Down.
В том случае, когда пользователь нажимает клавишу Set HotKey, обработчик считывает новую комбинацию клавиш активизации из органа управления Hot Key, посылая последнему сообщение HKM_GETHOTKEY , и записывает ее в переменную wHotKey.
Далее полученная комбинация клавиш устанавливается в качестве комбинации клавиш активизации при помощи сообщения WM_SETHOTKEY .
Функция WndProc_OnSysCommand обрабатывает сообщение WM_SYSCOMMAND , поступающее в главное окно приложения в том случае, если пользователь нажмет комбинацию клавиш активизации.
Этот обработчик посылает главному окну приложения сообщение WM_COMMAND с кодом команды ID_FILE_OPTIONS. В результате на экране появится диалоговая панель Value Selection.