Поскольку при создании список не содержит элементов, его необходимо инициализировать при первом отображении содержащего его диалога. Это довольно просто, поскольку при активизации диалога его оконная функция получает сообщение WM_INITDIALOG, так что в DialogFunc() нужно добавить обработку этого сообщения:
case WM_INITDIALOG: // Инициализация списка
SendDlgItemMessage(hdwnd,ID_LB1,LB_ADDSTRING,
0,(LPARAM)"Яблоко");
SendDlgltemMessage(hdwnd,ID_LB1,LB_ADDSTRING,
0,(LPARAM)"Апельсин");
SendDlgltemMessage(hdwnd,ID_LB1,LB_ADDSTRING,
0,(LPARAM)"Груша");
SendDlgltemMessage(hdwnd,ID_LB1,LB_ADDSTRING,
0,(LPARAM)"Виноград");
return 1;
Этот фрагмент программы заносит в список элементы Яблоко, Апельсин, Груша и Виноград. Каждый вызов функции SendDlgItemMessage() добавляет новую строку в список. Функция SendDlgItemMessage() направляет списку команду LB_ADDSTRING. Указатель на добавляемую строку содержится в параметре lParam (тип указателя надо преобразовать к LPARAM). В данном случае строки добавляются в список в том порядке, в котором передаются. В зависимости от типа списка добавляемые элементы могут сортироваться в алфавитном порядке. Если количество включаемых в список элементов превышает число элементов, которые можно отобразить в списке, к окну списка автоматически добавляется линейка прокрутки.
Выбор элементов списка. После инициализации список готов к работе с ним. Существует два способа эыбора элементов в списке. Во-первых, это можно сделать двойным щелчком мыши на выбираемом элементе. В этом случае оконной функции диалога будет направлено сообщение WM_COMMAND, в котором LOWORD(wParam) будет содержать идентификатор окна списка, a HIWORD(wParam) – сообщение LBN_DBLCLK. Двойной щелчок мыши обычно означает, что программа должна обработать выбор сразу же. Во-вторых, пользователь может просто изменить выбранный элемент списка, используя клавиатуру или мышь. В этом случае сообщение в программу не посылается, выбранный элемент запоминается, так что программа может запросить у списка номер этого элемента. Оба подхода иллюстрируются в приведенном ниже примере.
Если выбран какой-нибудь элемент списка, можно определить его номер, послав списку сообщение LB_GETCURSEL. В ответ список возвратит номер выбранного элемента. Если никакой элемент не выбран, список возвращает LB_ERR(-1).
Чтобы продемонстрировать процедуру обработки выбора элементов списка, добавьте во вложенный оператор switch в функции DialogFunc() следующий фрагмент.
case ID_LB1: // Обработка сообщения LBN_DBLCLK списка
// Если это, конечно, LBN_DBLCLK
if(HIWORD(wParam) == LBN_DBLCLK)
{ // Получить индекс выбранного элемента
i = SendDlgItemMessage(hdwnd,ID_LB1,
LB_GETCURSEL, 0, 0L);
sprintf(str,"Индекс выбранного элемента %d", i);
MessageBox(hdwnd, str,"Сделан выбор", МВ_ОК);
}
return 1;
case IDD_SELFRUIT: // Нажата кнопка "Выбери фрукт"
{
i = SendDlgItemMessage(hdwrtd, ID_LB1,
LBJ3ETCURSEL, 0, 0L);
if(i > -1)
sprintf(str,"Индекс выбранного элемента %d", i);
else
sprintf(str,"Фрукт не выбран");
MessageBox(hdwnd, str, "Сделан выбор", МВ_ОК);
return 1;
При двойном щелчке мыши на элементе списка будет появляться окно сообщения, отображающее индекс выбранного элемента. То же произойдет и при нажатии кнопки Выбери фрукт.
Пример 5-2. Для удобства приведем полный текст программы отображения диалога со списком. (Не забудьте внести соответствующие изменения а файлы Mydialog.h и Mydialog.rc).
// Демонстрация списка
#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 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)
{
switch(message)
{
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDM_DIALOG1:
DialogBox(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:
EndDialog(hdwnd,0);
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 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;
}
Пример работы этой программы показан на рис. 5.2.
Окно ввода
Окно ввода будет последним элементом управления, который мы добавим в диалог в этой главе. Окна ввода применяются для ввода текстовых строк. Перед добавлением окна ввода в программе необходимо описать его в файле ресурсов. В данном случае следует изменить Mydialog.rc так, чтобы описание диалога выглядело следующим образом:
MYDB DIALOG 18, 18, 142, 92
CAPTION "Первый диалог"
STYLE DS_MODALFRAME|WS_POPUP|WS_CAPTION|WS_SYSMENU
{
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
PUSHBUTTON "Конец ввода", IDOK, 68, 22, 60, 14,
WS_CHILD|WS_VISIBLE|WS_TABSTOP
LISTBOX ID_LB1, 2, 10, 47, 28, LBS_NOTIFY|WS_CHILD|
WS_VISIBLE|WS_BORDER|WSJVSCROLL|WS_TABSTOP
EDITTEXT ID_EB1, 68, 8, 72, 12, ES_LEFT|
ES_AUTOHSCROLL|WS_CHILD|WS_VISIBLE|WS_BORDER|
WS_TABSTOP
Рис. 5.2. Пример диалога со списком
В этой версии файла ресурсов добавлена кнопка Конец ввода, нажатие которой означает окончание ввода текста. Кроме того, добавлено само окно ввода.
Оператор EDITTEXT создает окно ввода в диалоге:
EDITTEXT ID, X, Y, Width, Height[, стиль]
Здесь ID задает идентификатор элемента управления, Х и Y – координаты его верхнего левого угла, Width и Height – размеры, а стиль определяет его внешний вид (стили, которые могут быть использованы, приведены в табл. 5.1).
Затем в Mydialog.h нужно добавить следующее макроопределение:
#define ID_ED1 107
Окна ввода могут не только принимать сообщения, но и генерировать их. Однако в нашем примере обработка всех сообщений не требуется. Вы увидите, что окна ввода автоматически выполняют все необходимые действия для редактирования текста, так что в процессе ввода текста Вашей программе не нужно будет взаимодействовать с окном ввода, – ей потребуется просто решить, когда следует получить текущее содержимое окна ввода. Для этого следует использовать функцию API GetDlgItemText():
UINT GetDlgltemText(HWND hdwnd, int nID,
LPSTR lpstr, int nMax);
Эта функция копирует содержимое окна ввода в строку-буфер, указатель на которую передается в параметре lpstr. При этом копируется не более nMax символов. Параметр hdwnd передает дескриптор окна диалога, a nID – идентификатор окна ввода.
Чтобы добавить в программу работу с окном ввода, дополните вложенный оператор switch в DialogFunc() приведенным ниже фрагментом кода. При нажатии кнопки Конец ввода откроется окно сообщения, содержащее текущий текст окна ввода.
case IDOK: // Нажата кнопка "Конец ввода",
// показать содержимое окна ввода
GetDlgItemText(hdwnd,ID_EB1,str,80);
MessageBox(hdwnd, str, "Содержимое окна ввода",
MB_OK);
return 1;
Макроимя IDOK было ранее определено в Windows.h.
Пример 5-3. С помощью сравнительно небольшой модификации программа, приведенная в примере 2, превращается в приложение с окном ввода. Проделайте эти изменения самостоятельно. На рис. 5.3 представлен результат работы программы с окном ввода.