Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

лекции / Shchupak_Yu._Win32_API_Razrabotka_prilozheniy_dlya_Windows

.pdf
Скачиваний:
0
Добавлен:
11.02.2026
Размер:
13.15 Mб
Скачать

Элементы управления главного окна

421

 

 

 

break;

case WM_PAINT:

hDC = BeginPaint(hWnd, &ps);

brightness = intensity[shapeData.id_bright - ID_DARK];

if (bShow) {

hBrush = CreateSolidBrush(RGB( shapeData.fRed? brightness : 0, shapeData.fGreen? brightness : 0, shapeData.fBlue? brightness : 0));

hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);

//Определение позиции и размеров фигуры с учетом

//уменьшения клиентской области из-за размещения

//панели инструментов и строки состояния GetClientRect(hWnd, &rect); GetWindowRect(hwndToolBar, &rcTB); tbHeight = rcTB.bottom - rcTB.top; GetWindowRect(hwndStatusBar, &rcSB); sbHeight = rcSB.bottom - rcSB.top;

x0 = rect.right / 2;

y0 = tbHeight + (rect.bottom - tbHeight - sbHeight) / 2;

// Координаты прямоугольника и эллипса if (shapeSize == MIN) {

x1 = x0 - W/2; y1 = y0 - H/2; x2 = x0 + W/2; y2 = y0 + H/2;

}

else {

x1 = 0; y1 = tbHeight;

x2 = rect.right; y2 = rect.bottom - sbHeight;

}

// Координаты ромба

pt[0].x = (x1 + x2) / 2; pt[0].y = y1; pt[1].x = x2; pt[1].y = (y1 + y2) / 2; pt[2].x = (x1 + x2) / 2; pt[2].y = y2; pt[3].x = x1; pt[3].y = (y1 + y2) / 2;

switch (shapeData.id_shape) {

 

case ID_RECTANGLE:

 

Rectangle(hDC, x1, y1, x2, y2);

break;

case ID_RHOMB:

Polygon(hDC, pt, 4); break; case ID_ELLIPSE:

Ellipse(hDC, x1, y1, x2, y2); break;

}

DeleteObject(SelectObject(hDC, hOldBrush));

}

EndPaint(hWnd, &ps); break;

case WM_DESTROY: PostQuitMessage(0);

продолжение

422

Глава 8. Элементы управления общего пользования

 

 

Листинг 8.5 (продолжение)

break;

default:

return DefWindowProc(hWnd, uMsg, wParam, lParam);

}

return 0;

}

//////////////////////////////////////////////////////////////////////

Приложение использует строку состояния в стандартном и простом режимах. Действия по формированию строки состояния, работающей в стандартном режиме, инкапсулированы в функцию UpdateStatusBar. Эта функция вызывается

при обработке сообщений WM_SIZE и WM_COMMAND.

Строка состояния, работающая в простом режиме, формируется кодом в бло ке обработки сообщения WM_MENUSELECT:

itemID = LOWORD(wParam); hClickMenu = (HMENU)lParam;

if (HIWORD(wParam) & MF_POPUP) { if (hClickMenu == hMenu)

submenuID = itemID; else

itemID += 100 * (submenuID + 1);

}

else if (!itemID) itemID = -1;

Алгоритм вычисления значения itemID реализует описанную выше процедуру однозначной идентификации пунктов подменю.

Дополнительного пояснения требуют две последние строки в этом фрагменте. В процессе отладки программы выяснилось, что при наведении курсора мыши на разделительную линию (SEPARATOR) Windows посылает сообщение WM_MENUSELECT, в котором LOWORD(wParam) равно нулю. Чтобы исключить интерпретацию этого зна чения как индекса подменю, добавлена последняя ветвь else. К счастью, старшее сло во параметра wParam в этой ситуации не содержит флага MF_POPUP. Это позволяет обнаружить разделитель и присвоить идентификатору itemID значение –1. Иденти фикатор со значением –1 гарантированно отсутствует в таблице строк приложения.

На рис. 8.10 показано окно работающего приложения StatusBar. Рекомендуем вам проверить работу приложения в других режимах.

Рис. 8.10. Приложение StatusBar. Строка состояния — в стандартном режиме

Другие элементы управления

423

 

 

 

Другие элементы управления

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

Progress bar, Slider и Spin.

Индикатор процесса

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

Индикатор процесса создается при помощи функции CreateWindow или Create WindowEx с указанием идентификатора PROGRESS_CLASS в качестве оконного клас са, например:

hwndProgressBar = CreateWindow(PROGRESS_CLASS, NULL, WS_CHILD | WS_VISIBLE, x, y, width, height, hwndParent, NULL, NULL, NULL);

По умолчанию индикатор процесса имеет горизонтальную ориентацию и за полняется отдельными маленькими прямоугольниками, окрашенными системным цветом COLOR_HIGHLIGHT1.

Если при вызове функции CreateWindowдополнительно указать стиль PBS_VERTICAL, то индикатор будет иметь вертикальную ориентацию. Термин «ориентация» здесь относится только к способу заполнения окна индикатора прямоугольниками: слева направо или снизу вверх. Форма же окна определяется только параметрами width

и height.

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

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

Интервал (range) индикатора процесса ассоциируется с полным выполнени ем операции. Он задается как пара целых чисел wMin и wMax. Текущая позиция (current position) отображает смещение от начала интервала и соответствует сте пени завершения операции. Оконная процедура индикатора процесса использует интервал и текущую позицию, чтобы определить процент заполнения окна инди катора прямоугольниками.

Для управления индикатором процесса используются сообщения, приведен ные в табл. 8.12 (полный список сообщений см. в MSDN).

Задавая значения wMin и wMax при определении интервала, выбирайте их из диапазона от 0 до 65 535. Если вы не определите интервал индикатора с помощью сообщения PBM_SETRANGE, то система использует установки по умолчанию, когда wMin = 0, а wMax = 100.

1Цвет, используемый Windows для подсвечивания выделенных элементов в дочерних окнах элемен тов управления.

424

 

Глава 8. Элементы управления общего пользования

 

Таблица 8.12. Сообщения для управления элементом Progress bar

 

 

 

 

Код сообщения

wParam

lParam

Описание

 

 

 

 

PBM_SETRANGE

0

MAKELPARAM

Установка интервала для индикатора

 

 

(wMin, wMax)

 

PBM_SETPOS

nNewPos

0

Установка текущей позиции

PBM_DELTAPOS

nInc

0

Изменение текущей позиции прибавлением

 

 

 

смещения nInc

PBM_SETSTEP

nStepInc

0

Установка шага приращения для индикатора

PBM_STEPIT

0

0

Изменение текущей позиции прибавлением

 

 

 

øàãà nStepInc

PBM_SETBARCOLOR

0

(COLORREF)

Установка цвета заполняемых прямоугольников

 

 

clrBar

 

PBM_SETBKCOLOR

0

(COLORREF)

Установка цвета фона

 

 

clrBk

 

 

 

 

 

Как видно из таблицы, текущее состояние индикатора можно изменять тремя аль тернативными способами. Для этого может использоваться сообщение PBM_SETPOS, PBM_DELTAPOS или PBM_STEPIT. В третьем способе текущая позиция изменяется при бавлением шага приращения nStepInc, который можно предварительно установить, отправив сообщение PBM_SETSTEP. Если вы не устанавливаете это значение, система использует значение по умолчанию nStepInc = 10.

Отметим, что если при обработке сообщения PBM_STEPIT индикатор достигнет значения wMax или превысит его, то его текущая позиция сбрасывается в значе ние wMin и индикатор процесса стартует сначала.

Два последних сообщения из табл. 8.12 позволяют изменить цветовые атрибу ты индикатора процесса.

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

Предположим, что размер загружаемого файла равен size байтов и файл чита ется порциями по DATA_CHUNK байтов. Чтобы упростить связь процесса загрузки файла с отображением степени завершения операции в индикаторе, будем счи тать, что wMin = 0, wMax = size / DATA_CHUNK, nStepInc = 1, а текущая позиция будет изменяться отправкой сообщения PBM_STEPIT.

Выбирая значение DATA_CHUNK, вы должны понимать, что величина wMax не может превышать значение 65 535.

Создайте новый проект с именем ProgressBar. Добавьте к настройкам проекта на вкладке Link библиотеку comctl32.lib. Скопируйте из папки проекта ToolTip фай лы KWndEx.h и KWndEx.cpp, после чего добавьте их в состав проекта. Также добавьте к приложению ресурс меню IDR_MENU1 с одним пунктом. Пункт меню должен иметь имя LoadFile и идентификатор IDM_LOAD_FILE.

Добавьте к проекту файл ProgressBar.cpp с текстом, приведенным в листинге 8.6.

Листинг 8.6. Проект ProgressBar

//////////////////////////////////////////////////////////////////////

// ProgressBar.cpp #include <windows.h> #include <commctrl.h>

Другие элементы управления

425

 

 

 

#include <stdio.h> #include <fstream> using namespace std;

#include "KWndEx.h" #include "resource.h"

#define ID_STATUSBAR 201 #define N_PARTS 2

#define DATA_CHUNK 64

#define FILE_NAME "ProgressBar.cpp"

HWND hwndStatusBar;

HWND hwndProgressBar;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //==================================================================== int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)

{

MSG msg;

KWndEx mainWnd("ProgressBar", hInstance, nCmdShow, WndProc, MAKEINTRESOURCE(IDR_MENU1), 100, 100, 400, 200);

while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg);

}

return msg.wParam;

}

//==================================================================== LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

HDC hDC; PAINTSTRUCT ps; char text[100]; RECT rect, r1;

int aWidths[N_PARTS];

 

ifstream file;

 

static int size;

// размер файла в байтах

static int range;

// диапазон для индикатора процесса

static int nBytesRead;

// число прочитанных байтов

double percentage;

 

char buf[DATA_CHUNK];

 

static int i;

 

MSG message;

 

switch (uMsg)

{

case WM_CREATE:

// Создание строки состояния

hwndStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE, "", hWnd, ID_STATUSBAR);

// Увеличиваем высоту строки состояния

продолжение

426 Глава 8. Элементы управления общего пользования

Листинг 8.6 (продолжение)

SendMessage(hwndStatusBar, SB_SETMINHEIGHT, 24, 0);

aWidths [0] = 50; aWidths [1] = -1;

SendMessage(hwndStatusBar, SB_SETPARTS, N_PARTS, (LPARAM)aWidths);

//Извлекаем координаты 1-ãî ïîëÿ SendMessage(hwndStatusBar, SB_GETRECT, 1, (LPARAM)&r1);

//Создание индикатора процесса

hwndProgressBar = CreateWindow(PROGRESS_CLASS, NULL, WS_CHILD | WS_VISIBLE,

r1.left + 3, r1.top + 3, r1.right - r1.left, r1.bottom - r1.top, hwndStatusBar, NULL, NULL, NULL);

break;

case WM_SIZE:

SendMessage (hwndStatusBar, WM_SIZE, wParam, lParam); break;

case WM_COMMAND:

switch (LOWORD(wParam))

{

case IDM_LOAD_FILE: // Открывем файл

file.open(FILE_NAME, ios::in | ios::binary); if (!file) {

MessageBox(hWnd, "Нет файла", NULL, MB_OK | MB_ICONSTOP); break;

}

// Определяем размер файла file.seekg(0, ios::end); size = file.tellg(); file.seekg(0, ios::beg);

// Настраиваем параметры индикатора процесса range = size / DATA_CHUNK; SendMessage(hwndProgressBar, PBM_SETRANGE, 0,

MAKELPARAM(0, range)); SendMessage(hwndProgressBar, PBM_SETSTEP, 1, 0); SendMessage(hwndProgressBar, PBM_SETPOS, 0, 0); InvalidateRect(hWnd, NULL, FALSE);

nBytesRead = 0; // Загрузка файла

while (!file.eof()) {

// Чтение порции данных file.read(buf, DATA_CHUNK); nBytesRead += DATA_CHUNK;

if (file.eof()) break;

//Здесь возможен вызов процедуры для обработки порции данных

//...

//Отображение процента выполненной операции

percentage = 100.0 * nBytesRead / size;

Другие элементы управления

427

 

 

 

sprintf(text, " %.0f %%", percentage); SendMessage(hwndStatusBar, SB_SETTEXT, 0, (LPARAM)text);

SendMessage(hwndProgressBar, PBM_STEPIT, 0, 0);

Sleep(100);

// Предотвращение зависания приложения if(PeekMessage(&message, hWnd, 0, 0, PM_REMOVE)) {

TranslateMessage(&message);

DispatchMessage(&message);

}

}

SendMessage(hwndStatusBar, SB_SETTEXT, 0, (LPARAM)" 100 %"); MessageBox(hWnd, "Файл загружен.", "Завершение операции",

MB_OK | MB_ICONINFORMATION);

// Сброс индикатора процесса в исходное положение SendMessage(hwndProgressBar, PBM_SETPOS, 0, 0); SendMessage(hwndStatusBar, SB_SETTEXT, 0, (LPARAM)" Ready"); break;

case IDM_EXIT:

SendMessage(hWnd, WM_DESTROY, 0, 0); break;

default:

break;

}

break;

case WM_PAINT:

hDC = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rect);

sprintf(text, "size = %d, DATA_CHUNK = %d, range = %d", size, DATA_CHUNK, range);

DrawText(hDC, text, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

EndPaint(hWnd, &ps); break;

case WM_DESTROY: PostQuitMessage(0); break;

default:

return DefWindowProc(hWnd, uMsg, wParam, lParam);

}

return 0;

}

//////////////////////////////////////////////////////////////////////

Имя загружаемого файла в этом примере задано следующей директивой:

#define FILE_NAME "ProgressBar.cpp"

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

428

Глава 8. Элементы управления общего пользования

 

 

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

SendMessage(hwndStatusBar, SB_GETRECT, 1, (LPARAM)&r1);

Загрузка файла осуществляется в цикле while. На каждой итерации цикла чи тается очередная порция данных, после чего окну индикатора процесса посыла ется сообщение PBM_STEPIT.

В теле цикла имеется инструкция Sleep(100), которая приостанавливает вы полнение программы на 100 мс. Преднамеренное замедление работы програм мы преследует демонстрационные цели. Дело в том, что загружаемый файл ProgressBar.cpp имеет небольшие размеры, и поэтому без этой задержки индика тор процесса будет заполнен практически мгновенно.

Также следует обратить внимание на фрагмент кода

if(PeekMessage(&message, hWnd, 0, 0, PM_REMOVE)) { TranslateMessage(&message); DispatchMessage(&message);

}

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

На рис. 8.11 показан вид работающего приложения ProgressBar после выбора команды меню LoadFile.

Рис. 8.11. Загрузка файла в приложении ProgressBar

Посмотрите, как изменится работа индикатора, если при его создании в функ ции CreateWindow задать дополнительный стиль PBS_SMOOTH.

Регулятор

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

Создание регулятора

Элемент управления Slider может быть создан с помощью функции CreateWindow или CreateWindowEx с указанием идентификатора TRACKBAR_CLASS в качестве окон ного класса, например:

Другие элементы управления

429

 

 

 

hwndSlider = CreateWindow(TRACKBAR_CLASS, NULL, WS_CHILD | WS_VISIBLE, x, y, width, height, hwndParent, NULL, NULL, NULL);

Кроме стилей WS_CHILD и WS_VISIBLE можно также задавать дополнительные стили, определяющие внешний вид элемента управления (табл. 8.13).

Таблица 8.13. Стили элемента управления Slider

Стиль

Описание

 

 

TBS_HORZ

Линейка имеет горизонтальную ориентацию (стиль по умолчанию)

TBS_VERT

Линейка имеет вертикальную ориентацию

TBS_AUTOTICKS

Линейка имеет метки для всех значений в заданном диапазоне значений. Без

 

этого стиля линейка может иметь метки только для начального и конечного

 

положений ползунка

TBS_NOTICKS

Исключает отображение каких-либо меток, в том числе и для начального

 

и конечного положений ползунка

TBS_RIGHT

Элемент отображает метки справа (снизу) от линейки; ползунок направлен

 

в ту же сторону. Этот стиль используется по умолчанию

TBS_LEFT

Элемент отображает метки слева (сверху) от линейки; ползунок направлен

 

в ту же сторону

TBS_BOTH

Элемент отображает метки с обеих сторон; ползунок имеет прямоугольную

 

форму

TBS_TOOLTIPS

Поддерживается всплывающая подсказка, отображающая текущую позицию

 

ползунка

 

 

Альтернативный способ создания регулятора — с помощью редактора диа логовых окон на этапе визуального проектирования формы диалога. В этом случае вы выбираете щелчком мыши элемент Slider на панели инструментов Controls и повторным щелчком помещаете регулятор в нужное место формы диалога.

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

Затем нужно вызвать окно свойств Slider Properties и на вкладке General в поле ID ввести идентификатор элемента управления. На вкладке Styles, показанной на рис. 8.12, можно задать дополнительные свойства регулятора.

Рис. 8.12. Свойства элемента Slider на вкладке Styles

Открывающийся список Orientation позволяет выбрать ориентацию элемен та управления: Horizontal (по умолчанию) или Vertical. Другой список, Point, пред назначен для выбора стиля размещения меток: Both (по умолчанию), Top/Left или Bottom/Right. Флажок Tick marks задает наличие меток, флажок Auto ticks за дает стиль TBS_AUTOTICKS, флажок Border определяет наличие рамки у элемента управления.

430

Глава 8. Элементы управления общего пользования

 

 

Создание регулятора с помощью редактора диалоговых окон является более простым способом. Именно эту технологию мы используем в рассматриваемом ниже примере разработки приложения Trackbar.

Параметры и состояние регулятора

С элементом управления Slider связан внутренний счетчик, определяющий его поведение. Счетчик имеет минимальное значение wMin и максимальное значение wMax. По умолчанию wMin = 0, а wMax = 100. Вы можете изменить диапазон регу лятора, послав ему сообщение TBM_SETRANGE.

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

Минимальный интервал, на который можно изменить состояние регулятора с помощью клавиш со стрелками, называется «строкой» (line). По умолчанию он равен единице. Размер «строки» можно изменить, послав регулятору сообщение

TBM_SETLINESIZE.

Более крупный интервал, на который можно изменить состояние регулятора с помощью клавиши PageUpили PageDown, называется «страницей» (page). По умол чанию размер «страницы» равен одной пятой части диапазона регулятора. Размер «страницы» можно изменить, послав регулятору сообщение TBM_SETPAGESIZE.

Если регулятор создан со стилем Auto ticks (TBS_AUTOTICKS), то линейка имеет метки во всем диапазоне значений с шагом wFreq, который по умолчанию равен единице. Вы можете изменить этот шаг, послав сообщение TBM_SETTICFREQ.

Действия пользователя и уведомляющие сообщения

Регулятор уведомляет свое родительское окно о действиях пользователя, посылая сообщение WM_HSCROLL или WM_VSCROLL — в зависимости от ориентации элемента уп равления (Horizontal или Vertical). В любом случае в младшем слове параметра wParam содержится код уведомления, а параметр lParam содержит дескриптор регулятора. Возможные коды уведомления приведены в табл. 8.14. Для кодов TB_THUMBPOSITION и TB_THUMBTRACK старшее слово параметра wParam содержит позицию ползунка.

Таблица 8.14. Коды уведомления от элемента управления Slider

Код уведомления

Значение

Описание

 

 

 

TB_LINEUP

0

Нажата клавиша «стрелка влево» (VK_LEFT) или клавиша

 

 

«стрелка вверх» (VK_UP) — ползунок сдвигается на вели-

 

 

чину «строки»

TB_LINEDOWN

1

Нажата клавиша «стрелка вправо» (VK_RIGHT) или кла-

 

 

виша «стрелка вниз» (VK_DOWN) — ползунок сдвигается

 

 

на величину «строки»

TB_PAGEUP

2

Нажата клавиша «Page Up» (VK_PRIOR) или щелчок

 

 

мышью на линейке левее или выше ползунка — ползунок

 

 

сдвигается на величину «страницы» (левее — для гори-

 

 

зонтальной ориентации регулятора, выше — для верти-

 

 

кальной ориентации)

TB_ PAGEDOWN

3

Нажата клавиша «Page Down» (VK_NEXT) или щелчок

 

 

мышью на линейке правее или ниже ползунка — ползунок

 

 

сдвигается на величину «страницы»