- •Московская финансово-промышленная академия
- •Содержание
- •Глава 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. Линейки прокрутки
5.9. Использование немодального диалога
Рис. 5.3. Пример работы Win-приложения с окном ввода
В завершение данной главы преобразуем модальный диалог из предыдущего примера в немодальный. Использование немодального диалога потребует несколько больше усилий, чем использование модального, — в основном потому, что немодальный диалог является более независимым окном, нежели модальный. В процессе работы немодального диалога программа остается активной, так что диалог и породившее его окно продолжают получать сообщения. Таким образом, для включения в программу немодального диалога необходимо вставить дополнительный фрагмент в цикл обработки сообщений Вашей программы.
Для создания немодального диалога вместо функции DialogBox() используется функция API CreateDialog():
HWND CreateDialog(HINSTANCE hThisInst,
LPCSTR lpName,
HWND hwnd,
DLGPROC IpDFunc);
Здесь hThisInst – дескриптор текущего экземпляра приложения, который передается в качестве параметра в функцию WinMain(), lpName – имя диалога, определенное в файле ресурсов, hwnd — дескриптор родительского окна для диалога, а lpDFunc – указатель на функцию диалога. Функция диалога в данном случае должна быть описана так же, как и для модального диалога.
В отличие от модального немодальный диалог не отображается на экране после создания, и чтобы получить такое изображение, Вам может понадобиться вызов функции ShowWindow(). Однако если при определении диалога в файле ресурсов добавить стиль WS_VISIBLE, диалог будет отображаться автоматически.
Для завершения немодального диалога программа должна вызвать функцию DestroyWindow(), а не EndDialog(). Прототип функции DestroyWindow() имеет следующий вид:
BOLL DestroyWindow(HWND hwnd);
Параметр hwnd должен задавать дескриптор закрываемого окна (в данном случае диалога).
Поскольку главное окно Вашего приложения будет продолжать получать сообщения, когда немодальный диалог будет активным, необходимо внести изменения в цикл обработки сообщений. Для этого следует добавить вызов функции IsDialogMessage(), направляющей сообщения диалога Вашему немодальному диалогу:
BOOL IsDialogMessage(HWND hdwnd, LPMSG msg);
Здесь hdwnd содержит дескриптор окна немодального диалога, a msg – сообщение, полученное в функции GetMessage(). Эта функция возвращает ненулевое значение, если сообщение предназначено для диалога, и нуль в противном случае. Если сообщение предназначено для диалога, оно будет автоматически направлено ему. Таким образом, для работы с немодальным диалогом цикл обработки сообщений Вашей программы должен выглядеть следующим образом:
while(GetMessage(&msg,NULL,0,0))
if(!IsDialogMessage(hDlg,&msg))
if(!TranslateAccelerator(hwnd,hAccel,&msg))
{
TranslateMessage(&msg); // использ.клавиатуры
DispatchMessage (&msg); // возврат к Windows
}
Как видите, сообщение обрабатывается обычным образом только в том случае, если оно не предназначено для диалога.
Создание немодального диалога. Преобразование модального диалога из предыдущего примера в немодальный потребует небольших изменений в программе. Прежде всего необходимо внести изменения в файл ресурсов Mydialog.rc. Поскольку немодальный диалог при создании не отображается автоматически, добавьте в определение диалога стиль WS_VISIBLE. Так как с момента создания файла Mydialog.rc мы внесли в него довольно много изменений, для удобства приведем этот файл целиком:
// Пример файла ресурсов, описывающего меню и диалог
#include "Mydialog.h"
#include <Windows.h>
MYMENU MENU
{
MENUITEM "Диалог &1", IDM_DIALOG1
MENUITEM "Диалог &2", IDM_DIALOG2
MENUITEM "Помощь", IDM_HELP
}
MYMENU ACCELERATORS
{
VK_F2, IDM_DIALOG1, VIRTKEY
VK_F3, IDM_DIALOG2, VIRTKEY
VK_F1, IDM_HELP, VIRTKEY
}
MYDB DIALOG 18, 18, 142, 92
CAPTION "Первый диалог"
STYLE DS_MODALFRAME|WS_POPUP|WS_CAPTION|WS_SYSMENU|
WS_VISIBLE
{
DEFPUSHBUTTON "Красный", IDD_RED, 57, 45, 36, 14,
WS_CHILD|WS_VISIBLE|WS_TABSTOP
PUSHBUTTON "Зеленый", IDD_GREEN, 95, 45, 36, 14,
WS_CHILD|WS_VISIBLE|WS_TABSTOP
PUSHBUTTON "Сброс", IDCANCEL, 52, 65, 37, 14,
WS_CHILD|WS_VISIBLE|WS_TABSTOP
PUSHBUTTON "Выбери фрукт", IDD_SELFRUIT,
2, 45, 50, 14, WS_CHILD|
WS_VISIBLE|WS_TABSTOP
LISTBOX ID_LB1, 2, 10, 47, 28, LBS_NOTIFY|WS_CHILD|
WS_VISIBLE| WS_BORDER|WS_VSCROLL|
WS_TABSTOP
EDITTEXT ID_EB1, 68, 8, 72, 12, ES_LEFT|
ES_AUTOHSCROLL|WS_CHILD|WS_VISIBLE|
WS_BORDER|WS_TABSTOP
PUSHBUTTON "Конец ввода", IDOK, 68, 22, 60, 14,
WS_CHILD|WS_VISIBLE|WS_TABSTOP
}
Далее в программу необходимо внести следующие изменения:
1) вызвать IsDialogMessage() в цикле обработки сообщений.
2) создать диалог, используя функцию CreateDialog(), а не функцию DialogBox().
3) для закрытия диалога заменить функцией DestroyWindows() функцию EndDialog().
Пример 5-4. Полный текст программы, использующей немодальный диалог (с внесенными изменениями), приводится ниже. Пример работы программы приведен на рис. 5.4. Обязательно попробуйте запустить эту программу, чтобы полностью понять разницу между модальным и немодальным диалогами.
Рис. 5.4. В немодальном режиме основная программа и диалог
работают параллельно
// Демонстрация немодального диалога
#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;
HWND hDlg; // Дескриптор окна диалога
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(!IsDialogMessage(hDlg,&msg))
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)
{
switch(message)
{
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDM_DIALOG1:
hDlg=CreateDialog(hInst,"MYDB",hwnd,
DialogFunc);
break;
case IDM_DIALOG2:
MessageBox(hwnd,
"Работает параллельно с первым",
"Второй диалог", 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)
{
long i;
char str[80];
switch(message)
{
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDCANCEL:
DestroyWindow(hdwnd);
return 1;
case IDD_RED:
MessageBox(hdwnd,
"Выбран Красный",
"Красный",MB_OK);
return 1;
case IDD_GREEN:
MessageBox(hdwnd,
"Выбран Зеленый",
"Зеленый",MB_OK);
return 1;
case ID_LB1: // Сообщение от списка, если
// это, конечно, LBN_DBLCLK
if(HIWORD(wParam) == LBN_DBLCLK)
{ // Получ. индекс выбран. элемента
i=SendDlgItemMessage(hdwnd, ID_LB1,
LB_GETCURSEL,
0, 0L);
sprintf
(str,
"Индекс выбранного элемента %d",
i);
MessageBox(hdwnd,str,"Сделан выбор",
MB_OK);
}
return 1;
case IDD_SELFRUIT: //Кнопка "Выбери фрукт"
i=SendDlgItemMessage(hdwnd,ID_LB1,
LB_GETCURSEL,
0, 0L);
if( i > -1)
sprintf
(str,
"Индекс выбранного элемента %d",
i);
else
sprintf(str,"Фрукт не выбран");
MessageBox(hdwnd,str,"Сделан выбор",
MB_OK);
return 1;
case IDOK: // Кнопка IDOK "Конец ввода"
GetDlgItemText(hdwnd,ID_EB1,str,80);
MessageBox(hdwnd, str, "Содержимое окна ввода",
MB_OK);
return 1;
}
case WM_INITDIALOG: // Инициализация списка
SendDlgItemMessage(hdwnd, ID_LB1,
LB_ADDSTRING,
0, (LPARAM)"Яблоко");
SendDlgItemMessage(hdwnd, ID_LB1,
LB_ADDSTRING,
0, (LPARAM)"Апельсин");
SendDlgItemMessage(hdwnd, ID_LB1,
LB_ADDSTRING,
0, (LPARAM)"Груша");
SendDlgItemMessage(hdwnd, ID_LB1,
LB_ADDSTRING,
0, (LPARAM)"Виноград");
return 1;
}
return 0;
}
В данной главе лишь поверхностно описаны те операции, которые можно выполнять с диалогом и различными элементами управления. Другие элементы управления рассматриваются далее. Вы можете самостоятельно поэкспериментировать, изучая свойства элементов управления.