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

47

0

Values of x

(значение х)

Values of y

(значение у)

Client area

(рабочая область)

Рис. 3.2 Координаты x и y в режиме отображения MM_TEXT

Контекст устройства также определяет "регион отсечения" (clipping region). Как вы уже узнали, задаваемый по умолчанию регион отсечения — это или вся рабочая область, если описатель контекста устройства получен из функции GetDC, или недействительный регион, если описатель контекста устройства получен из функции BeginPaint. Windows не выведет на экран ту часть строки символов, которая лежит вне региона отсечения. Если часть символа находится внутри отсекающей зоны, Windows выводит на экран только эту часть. Вывести что-нибудь за пределы рабочей области вашего окна очень непросто, поэтому не беспокойтесь о том, что это случится по невнимательности.

Системный шрифт

Контекст устройства также определяет шрифт, который Windows использует при выводе текста в рабочюю область. По умолчанию задается так называемый "системный шрифт" (system font) или (используя идентификатор заголовочных файлов Windows) SYSTEM_FONT. Системный шрифт — это шрифт, который Windows использует для текста заголовков, меню и окон диалога.

В ранних версиях Windows системный шрифт был фиксированным, т. е. у всех символов была одинаковая ширина, также как на пишущей машинке. Однако, начиная с Windows 3.0 (и до Windows 95 включительно), системный шрифт стал пропорциональным, т. е. разные символы имеют разную ширину. Например, символ W шире символа i. Так было сделано потому, что пропорциональный шрифт гораздо лучше читается, чем фиксированный. Но, как вы могли бы догадаться, изменение задаваемого по умолчанию шрифта с фиксированного на пропорциональный привело в негодность массу программ для первых версий Windows и потребовало от программистов изучить некоторые новые приемы работы с текстом.

Системный шрифт является "растровым шрифтом" (raster font). Это означает, что все символы определяются как пиксельные шаблоны. Распространяемые для продажи версии Windows включают в себя несколько системных шрифтов различных размеров для использования с различными видеоадаптерами. Когда производители новых видеоплат создают новый дисплейный драйвер, они также ответственны и за разработку системного шрифта, соответствующего разрешению дисплея. В противном случае, производителю пришлось бы указывать, какой именно системный шрифт из входящих в комплект Windows, может использоваться. Системный шрифт должен быть разработан таким образом, чтобы на экране помещалось, по крайней мере, 25 строк и 80 символов текста. Только это гарантирует, что имеется некоторое соответствие между размером экрана и размером шрифта в

Windows.

Размер символа

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

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

48

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

Для использования функции GetTextMetrics, во-первых, необходимо определить структурную переменную (которую обычно называют tm):

TEXTMETRIC tm;

Далее нужно получить описатель контекста устройства и вызвать GetTextMetrics:

hdc = GetDC(hwnd); GetTextMetrics(hdc, &tm); ReleaseDC(hwnd, hdc);

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

Метрические параметры текста. Подробности

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

Эти величины вполне объяснимы. Значение tmInternalLeading — это величина пустого пространства, отведенного для указания специальных знаков над символом. Если это значение равно 0, то помеченные прописные буквы делаются немного меньше, чтобы специальный символ поместился внутри верхней части символа. Значение tmExternalLeading

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

Вструктуре TEXTMETRIC имеется два поля, описывающих ширину символа: tmAveCharWidth (усредненная ширина символов строки) и tmMaxCharWidth (ширина самого широкого символа шрифта). Для фиксированного шрифта эти две величины одинаковы.

Впримерах программ этой главы используется другое значение ширины символа — средняя ширина прописных букв. Она может быть точно рассчитана как 150% от tmAveCharWidth.

tmExternalLeading

tmInternalLeading

tmAscent

tmHeight

Baseline

tmDescent

Рис. 3.3 Пять значений, определяющих вертикальный размер шрифта

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

49

символов. Не задавайте никаких фиксированных значений. Используйте функцию GetTextMetrics для получения этой информации.

Форматирование текста

Поскольку размеры системного шрифта не меняются в рамках одного сеанса работы с системой Windows, вам необходимо вызвать функцию GetTextMetrics только один раз при выполнении программы. Хорошо сделать этот вызов при обработке сообщения WM_CREATE в оконной процедуре. Сообщение WM_CREATE — это первое сообщение, которое принимает оконная процедура. Windows вызывает вашу оконную процедуру с сообщением WM_CREATE, когда вы вызываете в WinMain функцию CreateWindow.

Предположим, что вы пишите программу для Windows, которая выводит на экран несколько строк текста, появляющихся друг за другом в направлении к нижней границе рабочей области. Вы хотите получить значения высоты и ширины символов. Внутри оконной процедуры вы можете определить две переменные для хранения средней ширины символов (cxChar) и полной высоты символов (cyChar):

static int cxChar, cyChar;

Префикс с, добавленный к именам переменных, означает "счетчик" (сount) и в сочетании с x или y относится к длине или ширине. Эти переменные определяются как статические, поскольку они должны оставаться без изменений при обработке оконной процедурой других сообщений (таких как WM_PAINT). Если эти переменные определяются как глобальные вне какой бы то ни было функции, то нет необходимости определять их как статические.

Здесь представлен код обработки сообщения WM_CREATE:

case WM_CREATE:

hdc = GetDC(hwnd);

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

cyChar = tm.tmHeight + tm.tmExternalLeading;

ReleaseDC(hwnd, hdc); return 0;

Если вы не хотите учитывать межстрочное пространство (external leading), то можно использовать:

cyChar = tm.tmHeight;

От вас зависит, как использовать полученный размер символов для расчета координат при выводе информации. Самое простое — оставить пустое поле cyChar в верхней части рабочей области, и cxChar в ее левой части. Для вывода на экран нескольких строк текста с выравниванием по левому краю при вызове функции TextOut используйте следующее значение координаты x:

cxChar

Значение координаты y в TextOut:

cyChar *(1 + i)

где i — это номер строки, начиная с 0.

Вы часто будете сталкиваться с необходимостью выводить отформатированные числа как простые символьные строки. Если вы программировали для MS-DOS с использованием стандартных библиотечных функций языка С, вы, вероятно, для форматирования применяли функцию printf. В Windows функция printf не работает, поскольку printf предназначена для стандартного устройства вывода, а установка в Windows не имеет смысла.

В Windows есть аналогичная функция sprintf. Она работает точно также, как и функция printf, отличие заключается в том, что форматируемая строка помещается в символьный массив. Для вывода строки на экран можно затем использовать функцию TextOut. Очень удобно то, что возвращаемым значением sprintf является длина строки — вы можете передать это значение в TextOut в качестве параметра iLength. Следующий фрагмент программы показывает типовое использование функций sprintf и TextOut:

int iLength;

char szBuffer[40];

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

iLength = sprintf(szBuffer, "Сумма %d и %d равна %d", nA, nB, nA + nB); TextOut(hdc, x, y, szBuffer, iLength);

Для достаточно простых задач вы могли бы избежать вычисления iLength и объединить два оператора в один:

TextOut(hdc, x, y, szBuffer, sprintf(szBuffer, "Сумма %d и %d равна %d", nA, nB, nA + nB));

50

Это не очень красиво, но вполне работоспособно.

Если вам не нужно выводить числа с плавающей точкой, то вместо sprintf вам лучше использовать функцию wsprintf. Синтаксис функции wsprintf такой же, как и sprintf, но она включена в Windows, поэтому ее использование не увеличит размер вашего EXE-файла.

Соединим все вместе

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

Информация, получаемая при вызове функции Windows GetSystemMetrics, достаточно полезна. Эта функция возвращает информацию о размере различных графических элементов Windows, таких как значки, курсоры, панели заголовков и полосы прокрутки. В функции GetSystemMetrics имеется один параметр, называемый "индекс" (index). Этот индекс — один из 73 целых идентификаторов, определяемых в заголовочных файлах Windows. Возвращаемым значением GetSystemMetrics является целое, обычно это размер элемента, указанного в параметре.

Давайте напишем программу для вывода на экран некоторой части информации, получаемой при вызове функции GetSystemMetrics в простом формате: на каждой строке по одному элементу. Работать с этой информацией будет легче, если создать заголовочный файл, в котором нужно определить массив структур, содержащих идентификаторы индексов GetSystemMetrics и текст, который мы хотим выводить на экран для каждого возвращаемого функцией значения. Заголовочный файл назовем SYSMETS.H, он показан на рис. 3.4.

SYSMETS.H

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

 

SYSMETS.H --

System metrics display structure

-----------------------------------------------

*/

#define NUMLINES((int)(sizeof sysmetrics / sizeof sysmetrics [0]))

struct

{

int iIndex; char *szLabel; char *szDesc;

} sysmetrics [] =

{

SM_CXSCREEN,

SM_CYSCREEN,

SM_CXVSCROLL,

SM_CYHSCROLL,

SM_CYCAPTION,

SM_CXBORDER,

SM_CYBORDER,

SM_CXDLGFRAME,

SM_CYDLGFRAME,

SM_CYVTHUMB,

SM_CXHTHUMB,

SM_CXICON,

SM_CYICON,

SM_CXCURSOR,

SM_CYCURSOR,

SM_CYMENU,

SM_CXFULLSCREEN,

SM_CYFULLSCREEN,

SM_CYKANJIWINDOW,

SM_MOUSEPRESENT,

SM_CYVSCROLL,

SM_CXHSCROLL,

SM_DEBUG,

SM_SWAPBUTTON,

SM_RESERVED1,

SM_RESERVED2,

"SM_CXSCREEN",

"Screen width in pixels",

"SM_CYSCREEN",

"Screen height in pixels",

"SM_CXVSCROLL",

"Vertical scroll arrow width",

"SM_CYHSCROLL",

"Horizontal scroll arrow height",

"SM_CYCAPTION",

"Caption bar height",

"SM_CXBORDER",

"Window border width",

"SM_CYBORDER",

"Window border height",

"SM_CXDLGFRAME",

"Dialog window frame width",

"SM_CYDLGFRAME",

"Dialog window frame height",

"SM_CYVTHUMB",

"Vertical scroll thumb height",

"SM_CXHTHUMB",

"Horizontal scroll thumb width",

"SM_CXICON",

"Icon width",

"SM_CYICON",

"Icon height",

"SM_CXCURSOR",

"Cursor width",

"SM_CYCURSOR",

"Cursor height",

"SM_CYMENU",

"Menu bar height",

"SM_CXFULLSCREEN",

"Full screen client area width",

"SM_CYFULLSCREEN",

"Full screen client area height",

"SM_CYKANJIWINDOW",

"Kanji window height",

"SM_MOUSEPRESENT",

"Mouse present flag",

"SM_CYVSCROLL",

"Vertical scroll arrow height",

"SM_CXHSCROLL",

"Horizontal scroll arrow width",

"SM_DEBUG",

"Debug version flag",

"SM_SWAPBUTTON",

"Mouse buttons swapped flag",

"SM_RESERVED1",

"Reserved",

"SM_RESERVED2",

"Reserved",

51

SM_RESERVED3,

"SM_RESERVED3",

SM_RESERVED4,

"SM_RESERVED4",

SM_CXMIN,

"SM_CXMIN",

SM_CYMIN,

"SM_CYMIN",

SM_CXSIZE,

"SM_CXSIZE",

SM_CYSIZE,

"SM_CYSIZE",

SM_CXFRAME,

"SM_CXFRAME",

SM_CYFRAME,

"SM_CYFRAME",

SM_CXMINTRACK,

"SM_CXMINTRACK",

SM_CYMINTRACK,

"SM_CYMINTRACK",

SM_CXDOUBLECLK,

"SM_CXDOUBLECLK",

SM_CYDOUBLECLK,

"SM_CYDOUBLECLK",

SM_CXICONSPACING,

"SM_CXICONSPACING",

SM_CYICONSPACING,

"SM_CYICONSPACING",

SM_MENUDROPALIGNMENT,

"SM_MENUDROPALIGNENT",

SM_PENWINDOWS,

"SM_PENWINDOWS",

SM_DBCSENABLED,

"SM_DBCSENABLED",

SM_CMOUSEBUTTONS,

"SM_CMOUSEBUTTONS",

SM_SHOWSOUNDS,

"SM_SHOWSOUNDS",

};

"Reserved",

"Reserved",

"Minimum window width", "Minimum window height", "Minimize/Maximize icon width", "Minimize/Maximize icon height", "Window frame width",

"Window frame height",

"Minimum window tracking width", "Minimum window tracking height", "Double click x tolerance", "Double click y tolerance", "Horizontal icon spacing", "Vertical icon spacing",

"Left or right menu drop", "Pen extensions installed", "Double-Byte Char Set enabled", "Number of mouse buttons", "Present sounds visually"

Рис. 3.4 SYSMETS.H

Программа для вывода этой информации называется SYSMETS1. Файлы, необходимые для создания SYSMETS.EXE (make-файл и файл с исходным текстом на С) приведены на рис. 3.5. Большинство операторов должны быть теперь вам понятны. За исключением имени программы, make-файл идентичен make-файлу программы HELLOWIN. В SYSMETS1.С функция WinMain фактически идентична HELLOWIN.

SYSMETS1.MAK

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

# SYSMETS1.MAK make file

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

sysmets1.exe : sysmets1.obj

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

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

SYSMETS1.C

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

 

SYSMETS1.C --

System Metrics Display Program No. 1

 

(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[] = "SysMets1";

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;

52

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. 1", WS_OVERLAPPEDWINDOW, 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;

char

szBuffer[10];

HDC

hdc;

int

i;

PAINTSTRUCT

ps;

TEXTMETRIC

tm;

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); return 0;

case WM_PAINT :

hdc = BeginPaint(hwnd, &ps);

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

{

TextOut(

hdc, cxChar, cyChar *(1 + i), sysmetrics[i].szLabel, strlen(sysmetrics[i].szLabel)

);

TextOut(

hdc, cxChar + 22 * cxCaps, cyChar *(1 + i), sysmetrics[i].szDesc,

53

strlen(sysmetrics[i].szDesc)

);

SetTextAlign(hdc, TA_RIGHT | TA_TOP);

TextOut(

hdc, cxChar + 22 * cxCaps + 40 * cxChar, cyChar *(1 + i), 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.5 Программа SYSMETS1

На рис. 3.6 показано окно программы SYSMETS1, работающей на VGA. Из информации в окне программы следует, что ширина экрана составляет 640 пикселей, а высота 480 пикселей. Эти два значения, также как и многие другие значения, выведенные в окне, могут отличаться для различных типов дисплеев.

Рис. 3.6 Вывод информации программой SYSMETS1

Оконная процедура программы SYSMETS1.С

Оконная процедура WndProc программы SYSMETS1.С обрабатывает три сообщения: WM_CREATE, WM_PAINT и WM_DESTROY. Сообщение WM_DESTROY обрабатывается точно также, как и в программе HELLOWIN, рассмотренной в главе 2.

Сообщение WM_CREATE является первым сообщением, получаемым оконной процедурой. Оно генерируется операционной системой Windows, когда функция CreateWindow создает окно. При обработке сообщения WM_CREATE SYSMETS1 получает контекст устройства для окна путем вызова функции GetDC, а также размеры

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