- •Московская финансово-промышленная академия
- •Содержание
- •Глава 1. Модель программирования приложений
- •1.1. Потребительские свойства Windows
- •1.2. Процессы в Windows и потоковая многозадачность
- •1.3. Динамические библиотеки
- •1.4. Программное обеспечение для создания Win-приложений
- •Спецификация префиксов венгерской нотации
- •Глава 2. Обзор возможностей программирования
- •2.1. Общий взгляд на программирование в Windows
- •2.2. Взаимодействие Windows с программой
- •2.3. Win32 api: прикладной интерфейс для Windows
- •2.4. Компоненты окна
- •2.5. Основы приложений Windows
- •2.6. Каркас приложения Windows
- •2.7. Определение класса окна
- •Значения параметра lpszName
- •Наиболее употребляемые макросы для встроенных курсоров
- •Типы системных кистей
- •2.8. Создание окна
- •Наиболее распространенные стили
- •Параметры способа отображения nHow
- •2.9. Цикл обработки сообщений
- •2.10. Оконная функция
- •Типы префиксов
- •Глава 3. Обработка сообщений Windows
- •3.1. Что такое сообщения?
- •3.2. Обработка нажатая клавиш
- •Битовая карта lParam
- •3.3. Обработка сообщений wm_paint
- •3.4. Обработка сообщений «мыши»
- •3.5. Генерация сообщения wm_paint
- •3.6. Генерация сообщений таймера
- •Глава 4. Ресурсы и меню
- •4.1. Окна сообщений MessageBox
- •Значения функции MessageBox
- •Значения wMbType
- •4.2. Представляем меню
- •4.3. Использование ресурсов
- •Параметры menu
- •Параметры элементов меню
- •4.4. Включение меню в программу. Обработка команд
- •4.5. Включение акселераторов сменю
- •4.6. Загрузка таблицы акселераторов
- •Глава 5. Создание диалогов
- •5.1. Взаимодействие Win-диалогов с пользователем
- •5.2. Модальные диалоги: обработка сообщений
- •5.3. Активизация и создание простейшего диалога
- •5.4. Определение ресурсов диалога
- •Стили диалога
- •5.5. Оконная функция диалога
- •5.6. Основы работы со списками
- •Типы сообщений
- •5.7. Инициализация списка и выбор элементов
- •5.8. Окно ввода
- •5.9. Использование немодального диалога
- •Глава 6. Графические образы, иконки и курсоры
- •6.1. Иконка и курсор
- •6.2. Определение малой иконки
- •6.3. Работа с растровыми изображениями
- •Значения параметра dwRaster
- •6.4. Работа с несколькими растровыми изображениями
- •Глава 7. Более подробно об элементах управления
- •7.1. Работа с контрольными переключателями
- •7.2. Статические элементы
- •7.3. Работа с селекторными кнопками
- •7.4. Линейки прокрутки
7.2. Статические элементы
Статический элемент (static) – это элемент, который не получает и не генерирует никаких сообщений. Иными словами, статический элемент представляет собой средство описания чего-либо в диалоге и чаще всего просто отображается в виде текста или рамки, группирующей другие объекты. Ниже мы рассмотрим два статических элемента: центрированный текст и рамку группы. Эти элементы включаются в определение диалога в файл ресурсов с помощью операторов СТЕХТ и GROUPBOX соответственно.
СТЕХТ выводит строку, которая выравнивается по центру заданного прямоугольника. Общая форма этого оператора следующая:
СТЕХТ "текст", ID, X, Y, Width, Height[, стиль]
Строка "текст" задает текст, который должен отображаться в диалоге, a ID – идентификатор элемента. X и Y задают координаты, a Width и Height – размеры прямоугольника, в котором должен выводиться текст. Параметр стиль определяет вид статического элемента. Если стиль явно не задан, по умолчанию текст выводится по центру прямоугольной области. Следует отметить, что границы области в окне не отображаются, так что координаты и размеры прямоугольника просто задают область, в которой может размещаться текст.
Оператор GROUPBOX определяет элемент, представляющий собой рамку с заголовком. Этот элемент обычно используется для визуального группирования других элементов и может содержать заголовок (название) группы. Общая форма оператора GROUPBOX следующая:
GROUPBOX "заголовок", ID, X, Y, Width, Height[, стиль]
Здесь "заголовок" представляет собой заголовок группы, ID – идентификатор элемента, X и Y – координаты верхнего левого угла, a Width и Height – размеры элемента. Стиль определяет вид рамки группы. Чаще всего этот параметр не указывается.
Пример 7-3. Чтобы увидеть, что произойдет при добавлении статических элементов, добавьте в файл ресурсов следующие строки из предыдущего примера:
GROUPBOX "Переключатели", ID_GT1, 1, 1, 53, 34
СТЕХТ "Это текст", ID_CT1, 1, 44, 50, 24
Рис. 7.2. Диалог с добавленными статическими элементами
После этого перекомпилируйте программу и вызовите диалог. Полученный диалог теперь будет выглядеть так, как показано на рис. 7.2. Заметьте, что хотя статические элементы изменили внешний вид диалога, его функции не изменились.
7.3. Работа с селекторными кнопками
В этом разделе описываются селекторные кнопки* (radio buttons), использующиеся для представления в окне множества опций, из которых можно выбрать только одну. Селекторная кнопка состоит из небольшой круглой кнопки и текста с описанием селекторной кнопки. Если кнопка заполнена, опция установлена, если нет – опция сброшена. Windows поддерживает два типа селекторных кнопок – устанавливаемые вручную (ручные) и автоматические. Ручные селекторные кнопки (как и ручные контрольные переключатели) требуют, чтобы все действия по управлению ими выполняла программа. Управление автоматическими селекторными кнопками выполняет сама Windows. Поскольку управление селекторными кнопками более сложно, чем управление контрольными переключателями, и поскольку автоматические селекторные кнопки используются наиболее часто, рассмотрим только этот тип селекторных кнопок.
Как и другие элементы управления, селекторные кнопки описываются в файле ресурсов при определении диалога. Для создания автоматических селекторных кнопок используется оператор AUTORADIOBUTTON:
AUTORADIOBUTTON "строка", ID, X, Y,
Width, Height[,стиль]
Здесь "строка" задает текст, a ID – идентификатор селекторной кнопки. Координаты верхнего левого угла задаются параметрами X и Y, a ширина и высота – параметрами Width и Height. Стиль задает вид селекторной кнопки. Если этот параметр не указан, стиль устанавливается по умолчанию, то есть строка отображается справа от маленькой кнопки и пользователь может переключаться к селекторной кнопке с помощью клавиши [Tab].
Как уже упоминалось, селекторные кнопки используются для представления группы опций, из которых можно выбрать только одну. Если в такой группе используются автоматические селекторные кнопки, Windows управляет ими таким образом, чтобы в каждый момент времени была выбрана только одна из них. То есть, если пользователь выбирает одну из селекторных кнопок, ранее выбранная кнопка автоматически очищается, и поэтому невозможно выбрать более одной селекторной кнопки одновременно.
Селекторная кнопка (в том числе и автоматическая) может быть установлена в нужное состояние программно, если направить ей сообщение BM_SETCHECK, используя функцию API SendDlgItemMessage(). Значение wParam при этом определяет будущее состояние кнопки: если оно равно 1, то кнопка выбрана, если 0 – то нет. По умолчанию все кнопки изначально очищены.
С помощью функции SendDlgItemMessage() можно выбрать более одной селекторной кнопки одновременно либо сбросить все селекторные кнопки. Однако нормальный стиль использования селекторных кнопок в Windows предполагает, что в каждый момент времени может быть выбрана одна, и только одна, селекторная кнопка. Нарушать это правило не рекомендуется.
Состояние селекторной кнопки можно определить при помощи сообщения BM_GETCHECK. Если при этом селекторная кнопка возвращает 1, она выбрана, а если 0 – нет.
Чтобы включить селекторные кнопки в пример программы, добавьте в файл ресурсов определения диалога следующие строки. Заметьте, что при этом добавляется еще одна рамка группы для селекторных кнопок. Это, конечно, не обязательно, однако в диалогах Windows выделение групп элементов является общепринятым.
GROUPBOX "Селекторы", ID_GT2, 62, 1, 53, 34
AUTORADIOBUTTON "Селектор 1", ID_RB1, 64, 10, 50, 12
AUTORADIOBUTTON "Селектор 2", ID_RB2, 64, 22, 50, 12
Пример 7-4. Ниже приводится измененный текст программы предыдущего примера, в котором добавлен фрагмент работы с двумя селекторными кнопками. Поскольку эти кнопки автоматические, изменений в программе немного. Заметьте, что состояние селекторных кнопок сохраняется во внешних переменных rstatus1 и rstatus2. Значения этих переменных используются и для установки состояний селекторных кнопок при активизации диалога, и для отображения их состояния по команде меню Статус.
// Демонстрация селекторных переключателей
// (радиокнопок)
#include <Windows.h>
#include <String.h>
#include <Stdio.h>
#include "Mydialog.h"
LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM,LPARAM);
BOOL CALLBACK DialogFunc(HWND,UINT,WPARAM,LPARAM);
char szWinName[]="МоеОкно"; // Имя класса окна
HINSTANCE hInst;
int cbstatus1=0; // Для хранения состояния
int cbstatus2=0; // контрольных переключателей
int rbstatus1=0; // Для хранения состояния
int rbstatus2=0; // селекторных кнопок
int WINAPI WinMain(HINSTANCE hThisInst,
HINSTANCE hPrevInst,
LPSTR lpszArgs,
int nWinMode)
{
HWND hwnd;
MSG msg;
WNDCLASS wcl;
HACCEL hAccel;
// Определить класс окна
wcl.hInstance=hThisInst; // Дескриптор приложения
wcl.lpszClassName=szWinName; // Имя класса окна
wcl.lpfnWndProc=WindowFunc; // Функция окна
wcl.style=0; // Стиль по умолчанию
wcl.hIcon=LoadIcon(NULL,IDI_APPLICATION); // Иконка
wcl.hCursor=LoadCursor(NULL,IDC_ARROW); // Курсор
wcl.lpszMenuName="MYMENU"; // Меню
wcl.cbClsExtra=0; // Без дополнительной
wcl.cbWndExtra=0; // информации
wcl.hbrBackground= // Белый фон
(HBRUSH)GetStockObject(WHITE_BRUSH);
if(!RegisterClass(&wcl)) // Зарегистр. класс окна
return 0;
hwnd=CreateWindow(szWinName, // Создать окно
"Работа с селекторными кнопками",
WS_OVERLAPPEDWINDOW, // Стиль
CW_USEDEFAULT, // Х-координата
CW_USEDEFAULT, // Y-координата
CW_USEDEFAULT, // Ширина
CW_USEDEFAULT, // Высота
HWND_DESKTOP, // Нет родит. окна
NULL, // Нет меню
hThisInst, // Дескрип. приложения
NULL); // Без дополн. аргументов
hInst=hThisInst; // Дескрип. текущ. приложения
// Загрузить акселераторы
hAccel=LoadAccelerators(hThisInst,"MYMENU");
ShowWindow(hwnd,nWinMode); // Показать окно
UpdateWindow(hwnd); // Перерисовать содержимое
while(GetMessage(&msg,NULL,0,0))
{ // Запустить цикл обработки сообщений
if(!TranslateAccelerator(hwnd,hAccel,&msg))
{
TranslateMessage(&msg); // Исп. клавиатуры
DispatchMessage (&msg); // Возврат к Windows
}
}
return msg.wParam;
}
// Следующая функция вызывается операционной системой
// Windows и получает в качестве параметров сообщения
// из очереди сообщений данного приложения
LRESULT CALLBACK WindowFunc(HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
char str[255];
switch(message)
{
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_DIALOG1:
DialogBox(hInst,"MYDB",
hwnd,DialogFunc);
break;
case ID_STATUS: // Состояние переключат.
if(cbstatus1)
strcpy(str,
"Переключатель 1 выбран\n");
else
strcpy(str,
"Переключатель 1 не выбран\n");
if(cbstatus2)
strcat(str,
"Переключатель 2 выбран\n");
else
strcat(str,
"Переключатель 2 не выбран\n");
if(rbstatus1)
strcat(str,
"Селектор 1 выбран\n");
else
strcat(str,
"Селектор 1 не выбран\n");
if(rbstatus2)
strcat(str,
"Селектор 2 выбран\n");
else
strcat(str,
"Селектор 2 не выбран\n");
MessageBox(hwnd,str,"",MB_OK);
break;
case IDM_HELP:
MessageBox(hwnd,"Помощь","",MB_OK);
break;
}
break;
case WM_DESTROY: // Завершение программы
PostQuitMessage(0);
break;
default:
// Все сообщения, не обрабатываемые в данной
// функции, направляются на обработку по
// умолчанию
return DefWindowProc(hwnd,message,
wParam,lParam);
}
return 0;
}
// Простая функция диалога
BOOL CALLBACK DialogFunc(HWND hdwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG: // Инициализация диалога;
// установить состояние
// контрольн. переключателей
// и селектторных кнопок
SendDlgItemMessage(hdwnd,ID_CB1,
BM_SETCHECK,cbstatus1,0);
SendDlgItemMessage(hdwnd,ID_CB2,
BM_SETCHECK,cbstatus2,0);
SendDlgItemMessage(hdwnd,ID_RB1,
BM_SETCHECK,rbstatus1,0);
SendDlgItemMessage(hdwnd,ID_RB2,
BM_SETCHECK,rbstatus2,0);
return 1;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hdwnd,0);
return 1;
case IDOK:
// Обновить значения переменных,
// содержащих статус переключателей
cbstatus1=SendDlgItemMessage
(hdwnd,ID_CB1,
BM_GETCHECK,0,0);
// Выбран ли переключатель?
cbstatus2=SendDlgItemMessage
(hdwnd,ID_CB2,
BM_GETCHECK,0,0);
// Выбран ли переключатель?
// Обновить значения переменных,
// содержащих статус селекторных кнопок
rbstatus1=SendDlgItemMessage
(hdwnd,ID_RB1,
BM_GETCHECK,0,0);
// Выбран ли селектор?
rbstatus2=SendDlgItemMessage
(hdwnd,ID_RB2,
BM_GETCHECK,0,0);
// Выбран ли селектор?
EndDialog(hdwnd,0);
return 1;
case ID_CB1:
// Это ручной переключатель
// Пользователь его выбрал
// Поэтому нужно изменить его состояние
if(!SendDlgItemMessage(hdwnd,ID_CB1,
BM_GETCHECK,0,0))
SendDlgItemMessage(hdwnd,ID_CB1,
BM_SETCHECK,1,0);
else // Очистить его
SendDlgItemMessage(hdwnd,ID_CB1,
BM_SETCHECK,0,0);
return 1;
}
}
return 0;
}
Диалог, создаваемый этой программой, будет выглядеть так, как показано на рис. 7.3.