Файл scrlmet\wndproc.cpp
// ===================================== // Функция WndProc // =====================================
#define STRICT #include <windows.h>
#include <stdio.h>
#include <string.h>
void Print(HDC, int, char *);
static int cxChar, cyChar; static int cxCurrentPosition; static int cyCurrentPosition; static int nScrollPos;
LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static WORD cxClient, cyClient;
HDC hdc; // индекс контекста устройства PAINTSTRUCT ps; // структура для рисования static TEXTMETRIC tm; // структура для записи метрик // шрифта
switch (msg) { case WM_CREATE: { // Получаем контекст отображения, // необходимый для определения метрик шрифта hdc = GetDC(hwnd);
// Заполняем структуру информацией // о метрике шрифта, выбранного в // контекст отображения GetTextMetrics(hdc, &tm);
// Запоминаем значение ширины для // самого широкого символа cxChar = tm.tmMaxCharWidth;
// Запоминаем значение высоты букв с // учетом межстрочного интервала cyChar = tm.tmHeight + tm.tmExternalLeading;
// Инициализируем текущую позицию // вывода текста cxCurrentPosition = cxChar; cyCurrentPosition = 0;
// Освобождаем контекст ReleaseDC(hwnd, hdc);
// Начальное значение позиции nScrollPos = 0;
// Задаем диапазон изменения значений SetScrollRange(hwnd, SB_VERT, 0, 20, FALSE);
// Устанавливаем ползунок в начальную позицию SetScrollPos(hwnd, SB_VERT, nScrollPos, TRUE);
return 0; }
// Определяем размеры внутренней области окна case WM_SIZE: { cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0; }
// Сообщение от вертикальной полосы просмотра case WM_VSCROLL: { switch(wParam) { case SB_TOP: { nScrollPos = 0; break; } case SB_BOTTOM: { nScrollPos = 20; break; } case SB_LINEUP: { nScrollPos -= 1; break; } case SB_LINEDOWN: { nScrollPos += 1; break; } case SB_PAGEUP: { nScrollPos -= cyClient / cyChar; break; } case SB_PAGEDOWN: { nScrollPos += cyClient / cyChar; break; } case SB_THUMBPOSITION: { nScrollPos = LOWORD(lParam);
break; } // Блокируем для того чтобы избежать // мерцания содержимого окна при // перемещении ползунка case SB_THUMBTRACK: { return 0; } default: break; }
// Ограничиваем диапазон изменения значений if(nScrollPos >
20) nScrollPos = 20; if(nScrollPos < 0) nScrollPos = 0;
// Устанавливаем ползунок в новое положение SetScrollPos(hwnd, SB_VERT, nScrollPos, TRUE);
// Обновляем окно InvalidateRect(hwnd, NULL, TRUE);
return 0; }
case WM_PAINT: { // Инициализируем текущую позицию // вывода текста cxCurrentPosition = cxChar; cyCurrentPosition = 0;
hdc = BeginPaint(hwnd, &ps);
// Выводим параметры шрифта, полученные во // время создания окна при обработке // сообщения WM_CREATE Print(hdc, tm.tmHeight, "tmHeight");
Print(hdc, tm.tmAscent, "tmAscent");
Print(hdc, tm.tmDescent, "tmDescent");
Print(hdc, tm.tmInternalLeading, "tmInternalLeading");
Print(hdc, tm.tmExternalLeading, "tmExternalLeading");
Print(hdc, tm.tmAveCharWidth, "tmAveCharWidth");
Print(hdc, tm.tmMaxCharWidth, "tmMaxCharWidth");
Print(hdc, tm.tmWeight, "tmWeight");
Print(hdc, tm.tmItalic, "tmItalic");
Print(hdc, tm.tmUnderlined, "tmUnderlined");
Print(hdc, tm.tmStruckOut, "tmStruckOut");
Print(hdc, tm.tmFirstChar, "tmFirstChar");
Print(hdc, tm.tmLastChar, "tmLastChar");
Print(hdc, tm.tmDefaultChar, "tmDefaultChar");
Print(hdc, tm.tmBreakChar, "tmBreakChar");
Print(hdc, tm.tmPitchAndFamily, "tmPitchAndFamily");
Print(hdc, tm.tmCharSet, "tmCharSet");
Print(hdc, tm.tmOverhang, "tmOverhang");
Print(hdc, tm.tmDigitizedAspectX,"tmDigitizedAspectX");
Print(hdc, tm.tmDigitizedAspectY,"tmDigitizedAspectY");
EndPaint(hwnd, &ps);
return 0; }
// Обеспечиваем управление полосой просмотра // при помощи клавиатуры case WM_KEYDOWN: { // В зависимости от кода клавиши функция окна // посылает сама себе сообщения, которые // обычно генерируются полосой просмотра switch (wParam) { case VK_HOME: { SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0L);
break; } case VK_END: { SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0L);
break; } case VK_UP: { SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0L);
break; } case VK_DOWN: { SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0L);
break; } case VK_PRIOR: { SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0L);
break; } case VK_NEXT: { SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0L);
break; } } return 0; }
case WM_DESTROY: { PostQuitMessage(0);
return 0; } } return DefWindowProc(hwnd, msg, wParam, lParam);
}
// ========================================== // Функция для вывода параметров шрифта // в окно // ==========================================
void Print(HDC hdc, int tmValue, char *str) { char buf[80]; int i, y;
// Вычисляем начальную позицию для вывода y = cyCurrentPosition + cyChar * (1 - nScrollPos);
// Подготавливаем в рабочем буфере // и выводим в окно начиная с текущей // позиции название параметра sprintf(buf, "%s", str);
i = strlen(str);
TextOut(hdc, cxCurrentPosition, y, buf, i);
// Подготавливаем в рабочем буфере // и выводим в текущей строке окна // со смещением значение параметра sprintf(buf, "= %d", tmValue);
i = strlen(buf);
TextOut(hdc, cxCurrentPosition + 12 * cxChar, y, buf, i);
// Увеличиваем текущую позицию по // вертикали на высоту символа cyCurrentPosition += cyChar; }
При создании главного окна обработчик сообщения WM_CREATE получает информацию о метрике шрифта и сохраняет ее в структуре tm. Затем обработчик этого сообщения запоминает высоту и ширину букв системного шрифта и инициализирует текущую позицию для вывода текста. Далее устанавливается начальное значение позиции полосы просмотра, устанавливается диапазон изменения значений и устанавливается ползунок полосы просмотра:
nScrollPos = 0; SetScrollRange(hwnd, SB_VERT, 0, 20, FALSE);
SetScrollPos(hwnd, SB_VERT, nScrollPos, TRUE);
Так как всего выводится 20 параметров, окно содержит 20 строк. Поэтому устанавливается диапазон полосы просмотра (0, 20).
При изменении размера окна (а также в процессе создания окна) функция окна получает сообщение WM_SIZE, которое используется для определения размеров внутренней области окна:
case WM_SIZE: { cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0; }
Функция главного окна приложения содержит также обработчик сообщения WM_VSCROLL, поступающего от вертикальной полосы просмотра. Этот обработчик устанавливает новое значение для позиции полосы просмотра в переменной nScrollPos.
Небольшое замечание относительно сообщения WM_VSCROLL, для которого значение wParam равно SB_THUMBTRACK.
Напомним, что такое сообщение поступает в окно при передвижении ползунка по полосе просмотра. Мы обрабатывали это сообщение в предыдущем приложении, изменяя ширину статического органа управления синхронно с передвижениями ползунка. Теперь же мы игнорируем это сообщение:
case SB_THUMBTRACK: { return 0; }
Зачем мы так поступаем? Дело в том, что вслед за передвижением ползунка нам надо перерисовать главное окно приложения. А это длительный процесс. В тех случаях, когда невозможно обеспечить большую скорость перерисовки окна, нет смысла обрабатывать сообщение полосы просмотра с кодом SB_THUMBTRACK. Вы можете ограничиться обработкой сообщения с кодом SB_THUMBPOSITION, перерисовывая окно только после окончания процесса перемещения ползунка.
После обновления содержимого переменной nScrollPos функция окна устанавливает ползунок в новое положение и объявляет все окно требующим перерисовки:
SetScrollPos(hwnd, SB_VERT, nScrollPos, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
Это приведет к тому, что функции главного окна приложения будет передано сообщение WM_PAINT.
Обработчик этого сообщения мало отличается от аналогичного обработчика приложения TMETRICS, рассмотренного нами в предыдущем томе. Он выводит параметры шрифта с помощью функции Print, определенной в приложении.
Функция Print вычисляет начальную позицию по вертикали для вывода текста на основании текущей позиции полосы просмотра:
y = cyCurrentPosition + cyChar * (1 - nScrollPos);
Если значение переменной nScrollPos таково, что начальная позиция по вертикали меньше нуля, текст будет "выводиться" выше внутренней области окна. Строки, выведенные вне внутренней области окна, будут обрезаны.
Файл определения модуля для приложения SCRLMET приведен в листинге 2.19.