Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming_Windows_95_Part_I.pdf
Скачиваний:
96
Добавлен:
05.06.2014
Размер:
4.61 Mб
Скачать

55

Размер рабочей области

Если вы уже работаете с существующими приложениями для Windows, то обнаружите, что размер окон может меняться в очень широких пределах. Большинство (если предположить отсутствие в окнах меню или полос прокрутки) окон можно развернуть, и рабочая область займет весь экран, за исключением панели заголовка программы. Полный размер этой развернутой рабочей области становится доступным, благодаря функции GetSystemMetrics, использующей параметры SM_CXFULLSCREEN и SM_CYFULLSCREEN. Для дисплея типа VGA возвращаемые значения равны 640 и 461 пикселей. Минимальный размер окна может быть совершенно незначительным, иногда почти невидимым, когда рабочая область фактически исчезает.

Одним из наиболее общих способов определения размера рабочей области окна является обработка сообщения WM_SIZE в оконной процедуре. Windows посылает в оконную процедуру сообщение WM_SIZE при любом изменении размеров окна. Переменная lParam, переданная в оконную процедуру, содержит ширину рабочей области в младшем слове и высоту в старшем слове. Код программы для обработки этого сообщения часто выглядит следующим образом:

static int cxClient, cyClient;

[другие инструкции программы] case WM_SIZE:

cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); return 0;

Макросы LOWORD и HIWORD определяются в заголовочных файлах Windows. Также как cxChar и cyChar, переменные cxClient и cyClient определяются внутри оконной процедуры в качестве статических, так как они используются позднее при обработке других сообщений.

В конечном итоге за сообщением WM_SIZE будет следовать сообщение WM_PAINT. Почему? Потому что при определении класса окна мы следующим образом задали стиль класса:

CS_HREDRAW | CS_VREDRAW

Такой стиль класса указывает Windows на необходимость перерисовки как при горизонтальных изменениях размеров, так и при вертикальных.

Вы можете рассчитать полное число строк текста, которые помещаются внутри рабочей области окна по формуле:

cyClient / cyChar

Результат может быть равен 0, если высота рабочей области слишком мала для вывода на экран целого символа. Аналогично, примерное число строчных символов, которые вы сможете горизонтально изобразить в рабочей области равно:

cxClient / cxChar

Если вы определяете cxChar и cyChar при обработке сообщения WM_CREATE, не беспокойтесь о возможном делении на 0 в этом выражении. Ваша оконная процедура получает сообщение WM_CREATE, когда WinMain вызывает CreateWindow. Первое сообщение WM_SIZE приходит несколько позднее, когда WinMain вызывает ShowWindow, благодаря этому cxChar и cyChar всегда являются положительными ненулевыми величинами.

Знание размера рабочей области окна является первым шагом в обеспечении возможности для пользователя двигать текст внутри рабочей области, если рабочая область недостаточно велика, чтобы вместить в себя что-либо целиком. Если вы хорошо знакомы с другими приложениями для Windows, имеющими аналогичные требования, вы, вероятно, знаете, что нам нужно: добавить такие великолепные средства, как полосы прокрутки.

Полосы прокрутки

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

Полосы прокрутки предназначены для просмотра информации как в вертикальном (движение вверх и вниз), так и в горизонтальном (движение вправо и влево) направлениях. Вы можете щелкнуть мышью на стрелке в любом конце полосы прокрутки или между стрелками. Бегунок ("scroll box" или "thumb") перемещается по длине полосы прокрутки, индицируя положение информации на экране относительно документа в целом. Вы также можете с помощью мыши переместить бегунок в конкретное положение. На рис. 3.7 показано рекомендуемое использование вертикальной полосы прокрутки для просмотра текста.

56

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

Щелкните здесь для прокрутки на

Щелкните здесь для одну строку вверх прокрутки на одну

страницу вверх

Переместите бегунок для перехода в нужное место

Щелкните здесь для прокрутки на одну страницу вниз

Щелкните здесь для прокрутки на одну строку вниз

Рис. 3.7 Вертикальная полоса прокрутки

Вставить в ваше окно приложения вертикальную или горизонтальную полосу прокрутки очень просто. Все, что вам нужно сделать, это включить идентификатор WS_VSCROLL (вертикальная прокрутка) и WS_HSCROLLW (горизонтальная прокрутка) или оба сразу в описание стиля окна в инструкции CreateWindow. Эти полосы прокрутки всегда размещаются у правого края или в нижней части окна и занимают всю высоту или ширину рабочей области. Рабочая область не включает в себя пространство, занятое полосами прокрутки. Ширина вертикальной полосы прокрутки и высота горизонтальной постоянны для конкретного дисплейного драйвера. Если вам необходимы эти значения, вы можете получить их (как вы могли бы заметить), вызвав функцию

GetSystemMetrics.

Windows обеспечивает всю логику работы мыши с полосами прокрутки. Однако, у полос прокрутки нет интерфейса клавиатуры. Если вы хотите дублировать клавишами управления курсором некоторые функции полос прокрутки, вы должны точно реализовать эту логику (как это делается, можно прочесть в главе 5, целиком посвященной клавиатуре).

Диапазон и положение полос прокрутки

Каждая полоса прокрутки имеет соответствующий "диапазон" (range) (два целых, отражающих минимальное и максимальное значение) и "положение" (position) (местоположение бегунка внутри диапазона). Когда бегунок находится в крайней верхней (или крайней левой) части полосы прокрутки, положение бегунка соответствует минимальному значению диапазона. Крайнее правое (или крайнее нижнее) положение бегунка на полосе прокрутки соответствует максимальному значению диапазона.

По умолчанию устанавливается следующий диапазон полосы прокрутки: 0 (сверху или слева) и 100 (снизу или справа), но диапазон легко изменить на какое-нибудь более подходящее для вашей программы значение:

SetScrollRange(hwnd, iBar, iMin, iMax, bRedraw);

Параметр iBar равен либо SB_VERT, либо SB_HORZ, iMin и iMax являются минимальной и максимальной границами диапазона, а bRedraw устанавливается в TRUE, если Вы хотите, чтобы Windows перерисовала полосы прокрутки на основе вновь заданного диапазона.

Положение бегунка всегда дискретно. Например, полоса прокрутки с диапазоном от 0 до 4 имеет пять положений бегунка, как показано на рис. 3.8. Для установки нового положения бегунка внутри диапазона полосы прокрутки можно использовать функцию SetScrollPos:

SetScrollPos(hwnd, iBar, iPos, bRedraw);

Параметр iPos — это новое положение бегунка, оно должно быть задано внутри диапазона от iMin до iMax. Для получения текущего диапазона и положения полосы прокрутки в Windows используются похожие функции

(GetScrollRange и GetScrollPos).

57

Если в вашей программе используются полосы прокрутки, вы совместно с Windows берете на себя ответственность за поддержку полос прокрутки и обновление положения бегунка. Далее перечислены сферы ответственности Windows по поддержке полос прокрутки:

Управляет логикой работы мыши с полосой прокрутки.

Обеспечивает временную "инверсию цвета" при нажатии на кнопку мыши на полосе прокрутки.

Перемещает бегунок в соответствие с тем, как внутри полосы прокрутки его перемещает пользователь.

Отправляет сообщения полосы прокрутки в оконную процедуру для окна, содержащего полосу прокрутки. Ниже представлены сферы ответственности вашей программы:

Инициализация диапазона полосы прокрутки.

Обработка сообщений полосы прокрутки.

Обновление положения бегунка полосы прокрутки.

Положение 0

Положение 1

Положение 2

Положение 3

Положение 4

Положение 0

Положение 1

Положение 2

Положение 3

Положение 4

Рис. 3.8 Полосы прокрутки с пятью положениями бегунков

Сообщения полос прокрутки

Windows посылает оконной процедуре асинхронные сообщения WM_VSCROLL и WM_HSCROLL, когда на полосе прокрутки щелкают мышью или перетаскивается бегунок. Каждое действие мыши на полосе прокрутки вызывает появление по крайней мере двух сообщений, одного при нажатии кнопки мыши и другого, когда ее отпускают.

Младшее слово параметра wParam, которое объединяет сообщения WM_VSCROLL и WM_HSCROLL — это число, показывающее, что мышь осуществляет какие-то действия на полосе прокрутки. Его значения соответствуют определенным идентификаторам, которые начинаются с SB_, что означает "полоса прокрутки" (scroll bar). Хотя в некоторых из этих идентификаторов используются слова "UP" и "DOWN", они применяются и к горизонтальным и к вертикальным полосам прокрутки, как показано на рис. 3.9. Ваша оконная процедура может получить множество сообщений типа SB_LINEUP, SB_PAGEUP, SB_LINEDOWN или SB_PSGEDOWN, если кнопка мыши остается нажатой при перемещении по полосе прокрутки. Сообщение SB_ENDSCROLL показывает, что кнопка мыши отпущена. Как правило, сообщения SB_ENDSCROLL можно игнорировать.

Если младшее слово параметра wParam равно SB_THUMBTRACK или SB_THUMBPOSITION, то старшее слово wParam определяет текущее положение полосы прокрутки. Это положение находится между минимальным и максимальным значениями диапазона полосы прокрутки. Во всех других случаях при работе с полосами прокрутки старшее слово wParam следует игнорировать. Вы также можете игнорировать параметр lParam, который обычно используется для полос прокрутки, создаваемых в окнах диалога.

58

Нажата: SB_LINEUP

Отпущена: SB ENDSCROLL

Нажата: SB_PAGEUP

Отпущена: SB_ ENDSCROLL

Нажата: SB_THUMBTRACK

Отпущена:

Нажата: SB_PAGEDOWN

Отпущена: SB_ENDSCROLL

Нажата: SB_LINEDOWN

Отпущена: SB_ENDSCROLL

Рис. 3.9 Значения идентификаторов для параметра wParam сообщений

полосы прокрутки

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

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

Однако, если у вас есть возможность быстро обновлять содержимое экрана, вы можете захотеть включить в программу обработку сообщений SB_THUMBTRACK. Но знайте, что те пользователи, которые обнаружат, что ваша программа мгновенно реагирует на перемещение бегунка по полосе прокрутки, несомненно будут пытаться двигать его как можно быстрее, чтобы понаблюдать, сможет ли программа отследить это движение — и они будут несказанно удовлетворены, если этого не произойдет.

Прокрутка в программе SYSMETS

Достаточно объяснений. Самое время использовать этот материал на практике. Давайте начнем с простого. Начнем мы с вертикальной прокрутки, поскольку требуется она гораздо чаще. Горизонтальная прокрутка может подождать. SYSMETS2 представлена на рис. 3.10.

Обновленный вызов функции CreateWindow добавляет вертикальную полосу прокрутки к окну, благодаря включению в описание стиля окна в CreateWindow идентификатора WS_VSCROLL:

WS_OVERLAPPEDWINDOW | WS_VSCROLL

SYSMETS2.MAK

#------------------------

# SYSMETS2.MAK make file

#------------------------

sysmets2.exe : sysmets2.obj

$(LINKER) $(GUIFLAGS) -OUT:sysmets2.exe sysmets2.obj $(GUILIBS)

sysmets2.obj : sysmets2.c sysmets.h $(CC) $(CFLAGS) sysmets2.c

59

SYSMETS2.C

/*----------------------------------------------------

SYSMETS2.C -- System Metrics Display Program No. 2

(c) Charles Petzold, 1996

----------------------------------------------------*/

#include <windows.h> #include <string.h> #include "sysmets.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

{

static char szAppName[] = "SysMets2";

HWND

hwnd;

MSG

msg;

WNDCLASSEX

wndclass;

wndclass.cbSize

= sizeof(wndclass);

wndclass.style

= CS_HREDRAW | CS_VREDRAW;

wndclass.lpfnWndProc

= WndProc;

wndclass.cbClsExtra

= 0;

wndclass.cbWndExtra

= 0;

wndclass.hInstance

= hInstance;

wndclass.hIcon

= LoadIcon(NULL, IDI_APPLICATION);

wndclass.hCursor

= LoadCursor(NULL, IDC_ARROW);

wndclass.hbrBackground

=(HBRUSH) GetStockObject(WHITE_BRUSH);

wndclass.lpszMenuName

= NULL;

wndclass.lpszClassName

= szAppName;

wndclass.hIconSm

= LoadIcon(NULL, IDI_APPLICATION);

RegisterClassEx(&wndclass);

hwnd = CreateWindow( szAppName,

"Get System Metrics No. 2", WS_OVERLAPPEDWINDOW | WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL

);

ShowWindow(hwnd, iCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

static int

cxChar, cxCaps, cyChar, cyClient, iVscrollPos;

char

szBuffer[10];

HDC

hdc;

int

i, y;

PAINTSTRUCT

ps;

TEXTMETRIC

tm;

60

switch(iMsg)

{

case WM_CREATE :

hdc = GetDC(hwnd);

GetTextMetrics(hdc, &tm); cxChar = tm.tmAveCharWidth;

cxCaps =(tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2; cyChar = tm.tmHeight + tm.tmExternalLeading;

ReleaseDC(hwnd, hdc);

SetScrollRange(hwnd, SB_VERT, 0, NUMLINES, FALSE); SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE); return 0;

case WM_SIZE :

cyClient = HIWORD(lParam); return 0;

case WM_VSCROLL : switch(LOWORD(wParam))

{

case SB_LINEUP : iVscrollPos -= 1; break;

case SB_LINEDOWN : iVscrollPos += 1; break;

case SB_PAGEUP :

iVscrollPos -= cyClient / cyChar; break;

case SB_PAGEDOWN :

iVscrollPos += cyClient / cyChar; break;

case SB_THUMBPOSITION :

iVscrollPos = HIWORD(wParam); break;

default : break;

}

iVscrollPos = max(0, min(iVscrollPos, NUMLINES));

if (iVscrollPos != GetScrollPos(hwnd, SB_VERT))

{

SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);

InvalidateRect(hwnd, NULL, TRUE);

}

return 0;

case WM_PAINT :

hdc = BeginPaint(hwnd, &ps);

for(i = 0; i < NUMLINES; i++)

{

y = cyChar *(1 - iVscrollPos + i);

TextOut(

hdc, cxChar, y,

61

sysmetrics[i].szLabel,

strlen(sysmetrics[i].szLabel)

);

TextOut(

hdc, cxChar + 22 * cxCaps, y, sysmetrics[i].szDesc, strlen(sysmetrics[i].szDesc)

);

SetTextAlign(hdc, TA_RIGHT | TA_TOP);

TextOut(

hdc, cxChar + 22 * cxCaps + 40 * cxChar, y, szBuffer,

wsprintf(

szBuffer, "%5d", GetSystemMetrics(sysmetrics[i].iIndex)

)

);

SetTextAlign(hdc, TA_LEFT | TA_TOP);

}

EndPaint(hwnd, &ps); return 0;

case WM_DESTROY : PostQuitMessage(0); return 0;

}

return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

Рис. 3.10 Программа SYSMETS2

К оконной процедуре WndProc добавляются две строки для установки диапазона и положения вертикальной полосы прокрутки во время обработки сообщения WM_CREATE:

SetScrollRange(hwnd, SB_VERT, 0, NUMLINES, FALSE);

SetScrollPass(hwnd, SB_VERT, iVscrollPos, TRUE);

Структура sysmetrics содержит NUMLINES строк текста, поэтому границы диапазона полосы прокрутки устанавливается от 0 до NUMLINES. Каждое положение полосы прокрутки соответствует строке текста в верхней части рабочей области. Если бегунок полосы прокрутки находится в положении 0, то в окне сверху остается пустая строка. При увеличении значения, определяющего положение полосы прокрутки, путем перемещения бегунка вниз, текст будет подниматься. Если положение бегунка полосы прокрутки находится в крайнем нижнем положении полосы, то последняя строка текста находится на самом верху рабочей области окна.

Для упрощения обработки сообщений WM_VSCROLL статическая переменная с именем iVscrollPos определяется внутри оконной процедуры WndProc. Эта переменная соответствует текущему положению бегунка полосы прокрутки. Что касается сообщений SB_LINEUP и SB_LINEDOWN, то все, что нужно сделать, это изменить положение прокрутки на 1. При получении сообщений SB_PAGEUP и SB_PAGEDOWN появляется возможность перемещать текст постранично (вернее "поэкранно"), или, что то же самое, изменять положение полосы прокрутки на величину, равную cyClient деленную на cyChar. Для SB_THUMBPOSITION новое положение бегунка определяется старшим словом wParam. Сообщения SB_ENDSCROLL и SB_THUMBTRACK игнорируются.

Затем параметр iVscrollPos устанавливается с использованием макросов min и max, чтобы гарантировать, что значение параметра будет находиться между минимальным и максимальным значениями диапазона. Если положение прокрутки изменилось, оно обновляется с помощью функции SetScrollPos и все окно делается недействительным путем вызова InvalidateRect.

При вызове функции InvalidateRect вырабатывается сообщение WM_PAINT. Когда исходная программа SYSMETS1 обрабатывала сообщение WM_PAINT, координата y для каждой строки рассчитывалась следующим образом:

Соседние файлы в предмете Операционные системы