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

72

соображений совместимости и экономии памяти по-прежнему поддерживает старые шрифты, основанные на битовых массивах (такие как системный шрифт по умолчанию).

Другие аспекты

Другие аспекты GDI не так легко классифицируются. Это:

Режимы масштабирования и преобразования. Хотя, по умолчанию, вывод задается в пикселях, существуют и другие возможности. Режимы масштабирования GDI позволяют вам рисовать, задавая размеры в дюймах (иногда, в долях дюйма), в миллиметрах, или других удобных вам единицах измерения. (Windows NT также поддерживает привычное "преобразование пространства", задаваемое матрицей 3× 3. Это дает возможность нелинейно менять размеры и вращать графические объекты. В Windows 95 это преобразование не поддерживается.)

Метафайлы. Метафайл — это набор вызовов команд GDI, сохраненный в двоичном виде. Метафайлы, в основном, используются для передачи изображений векторной графики через буфер обмена (clipboard).

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

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

Отсечение. Рисование может быть ограничено некоторой областью рабочего пространства окна. Это и называется отсечением, область отсечения может быть прямоугольной или любой другой, какую вы можете описать математически как набор коротких отрезков. Отсечение, как правило, задается регионом или путем.

Палитры. Использование привычных палитр обычно ограничено способностью дисплея показывать не более 256 цветов. Windows резервирует только 20 из этих цветов для использования системой. Вы можете изменять другие 236 цветов для точного отображения красок предметов реального мира как битовые образы.

Печать. Несмотря на то, что эта глава посвящена отображению на экране дисплея, все, чему вы научитесь здесь, относится и к принтерам. (Смотри главу 15, где рассматривается печать.)

Контекст устройства

Перед тем, как начать рисовать, рассмотрим контекст устройства более подробно, чем в главе 3.

Если вы хотите рисовать на устройстве графического вывода (экране дисплея или принтере), сначала надо получить описатель контекста устройства (device context, DC). Передавая этот описатель, Windows тем самым дает вам право на использование самого устройства. Затем вы включаете этот описатель как параметр в функции GDI для того, чтобы сообщить Windows, на каком устройстве вы собираетесь рисовать.

Контекст устройства содержит много текущих атрибутов, определяющих поведение функций GDI при работе с устройством. Эти атрибуты позволяют включать в вызовы функций GDI только начальные координаты или размеры, и ничего больше из того, что требуется для отображения объекта на устройстве. Например, когда вы вызываете функцию TextOut, в ее параметрах вам надо указать только описатель контекста устройства, начальные координаты, сам выводимый текст и его длину. Вам не нужно указывать шрифт, цвет текста, цвет фона и межсимвольное расстояние, потому что эти атрибуты являются частью контекста устройства. Когда вы хотите изменить один из этих атрибутов, вы вызываете функцию, изменяющую значение атрибута в контексте устройства. Последующие вызовы функции TextOut будут использовать измененные значения атрибутов.

Получение описателя контекста устройства

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

Наиболее общий метод получения контекста устройства и его освобождения состоит в использовании функций BeginPaint и EndPaint при обработке сообщения WM_PAINT:

hdc = BeginPaint(hwnd, &ps);

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

EndPaint(hwnd, &ps);

73

Переменная ps — это структура типа PAINTSTRUCT. Поле hdc этой структуры — это описатель контекста устройства, который возвращается функцией BeginPaint. Структура PAINTSTRUCT содержит также структуру типа RECT с именем rcPaint (прямоугольник), определяющую прямоугольную область, содержащую недействительный (требующий перерисовки) регион клиентской области окна. Получив описатель контекста устройства от функции BeginPaint, вы можете рисовать только в пределах этого региона. Функция BeginPaint делает этот регион действительным.

Программы для Windows могут также получать описатель контекста устройства в теле обработчика сообщения, отличного от WM_PAINT:

hdc = GetDC(hwnd);

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

ReleaseDC(hwnd, hdc);

Полученный контекст устройства с описателем hwnd относится к клиентской (рабочей) области окна. Основная разница между использованием этих функций и комбинации функций BeginPaint и EndPaint состоит в том, что вы можете рисовать в пределах всей рабочей области окна, используя описатель контекста устройства, возвращенный функцией GetDC. Кроме того, функции GetDC и ReleaseDC не делают действительным (не требующим перерисовки) ни один недействительный регион клиентской области окна.

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

hdc = GetWindowDC(hwnd);

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

ReleaseDC(hwnd. hdc);

Этот контекст устройства включает заголовок окна, меню, полосы прокрутки и рамку окна в дополнение к клиентской области. Функция GetWindowDC редко используется в приложениях. Если вы хотите поэкспериментировать с ней, то вам следует обработать сообщение WM_NCPAINT ("nonclient paint", рисование неклиентской области), которое генерируется Windows для перерисовки неклиентской области окна.

Функции BeginPaint, GetDC и GetWindowDC получают контекст устройства, связанный с конкретным окном на экране. Более общая функция для получения описателя контекста устройства — это функция CreateDC:

hdc = CreateDC(pszDriver, pszDevice, pszOutput, pData);

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

DeleteDC(hdc);

Например, вы можете получить описатель контекста устройства всего дисплея так:

hdc = CreateDC("DISPLAY", NULL, NULL, NULL);

Запись вне вашего окна обычно не принята, но это удобно для некоторых редко используемых приложений. (Хотя это и не документировано, вы можете получить описатель контекста устройства для экрана дисплея посредством вызова функции GetDC с параметром NULL.) В главе 15 мы будем использовать эту функцию для получения описателя контекста устройства принтера.

Иногда вам нужно только получить некоторую информацию о контексте устройства, и не надо ничего рисовать. В этих случаях вы можете получить описатель так называемого "информационного контекста" (information context), используя функцию CreateIC. Параметры этой функции такие же, как у функции CreateDC, например:

hdcInfo = CreateIC("DISPLAY", NULL, NULL, NULL);

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

DeleteDC(hdcInfo);

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

При работе с битовыми образами иногда может быть полезно получить "контекст памяти" (memory device context):

hdcMem = CreateCompatibleDC(hdc);

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

DeleteDC(hdcMem);

Это достаточно общая концепция. Главное, что вам надо сделать, это выбрать битовый образ в контекст памяти, а затем вызвать функцию GDI для рисования битового образа. Мы обсудим это позднее в данной главе и используем рассмотренную методику в программе GRAFMENU из главы 10.

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

hdcMeta = CreateMetaFile(pszFilename);

[другие строки программы] hmf = CloseMetaFile(hdcMeta);

74

Пока контекст метафайла действителен вызов GDI, который вы осуществляете, используя hdcMeta, не вызывает вывода на устройство, а записывается в метафайл. Когда вы вызываете CloseMetaFile, описатель контекста становится недействительным. Функция возвращает описатель метафайла (hmf).

Получение информации из контекста устройства

Контекст устройства обычно описывает такие физические устройства как видеотерминалы или принтеры. Часто вам необходимо получить информацию об одном из этих устройств, такую как размер экрана (в терминах пикселей и физических единицах измерения) и его цветовые возможности. Вы можете получить эту информацию посредством вызова функции GetDeviceCaps:

iValue = GetDeviceCaps(hdc, iIndex);

Параметр iIndex — один из 28 идентификаторов, определенных в заголовочном файле Windows. Например, значение iIndex равное HORZRES заставляет функцию GetDeviceCaps вернуть ширину устройства в пикселях; значение VERTRES — высоту устройства в пикселях. Если hdc является описателем контекста устройства дисплея, то эту же информацию вы можете получить от функции GetSystemMetrics. Если hdc является описателем контекста устройства принтера, то тогда уже функция GetDeviceCaps возвращает высоту и ширину рабочей области принтера в пикселях.

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

Программа DEVCAPS1

Программа DEVCAPS1, приведенная на рис. 4.1, частично отображает информацию, доступную посредством вызова GetDeviceCaps с использованием контекста устройства для дисплея. (Вторая, расширенная версия программы, DEVCAPS2, будет приведена в главе 15 для получения информации о принтере.)

DEVCAPS1.MAK

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

# DEVCAPS1.MAK make file

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

devcaps1.exe : devcaps1.obj

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

devcaps1.obj : devcaps1.c $(CC) $(CFLAGS) devcaps1.c

DEVCAPS1.C

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

 

DEVCAPS1.C --

Device Capabilities Display Program No. 1

 

(c) Charles Petzold, 1996

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

*/

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

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

struct

{

int iIndex; char *szLabel; char *szDesc;

} devcaps [] =

{

HORZSIZE,

"HORZSIZE",

"Width in millimeters:",

VERTSIZE,

"VERTSIZE",

"Height in millimeters:",

HORZRES,

"HORZRES",

"Width in pixels:",

VERTRES,

"VERTRES",

"Height in raster lines:",

75

BITSPIXEL,

"BITSPIXEL",

"Color bits per pixel:",

PLANES,

"PLANES",

"Number of color planes:",

NUMBRUSHES,

"NUMBRUSHES",

"Number of device brushes:",

NUMPENS,

"NUMPENS",

"Number of device pens:",

NUMMARKERS,

"NUMMARKERS",

"Number of device markers:",

NUMFONTS,

"NUMFONTS",

"Number of device fonts:",

NUMCOLORS,

"NUMCOLORS",

"Number of device colors:",

PDEVICESIZE,

"PDEVICESIZE",

"Size of device structure:",

ASPECTX,

"ASPECTX",

"Relative width of pixel:",

ASPECTY,

"ASPECTY",

"Relative height of pixel:",

ASPECTXY,

"ASPECTXY",

"Relative diagonal of pixel:",

LOGPIXELSX,

"LOGPIXELSX",

"Horizontal dots per inch:",

LOGPIXELSY,

"LOGPIXELSY",

"Vertical dots per inch:",

SIZEPALETTE,

"SIZEPALETTE",

"Number of palette entries:",

NUMRESERVED,

"NUMRESERVED",

"Reserved palette entries:",

COLORRES,

"COLORRES",

"Actual color resolution:"

};

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

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

{

static char szAppName[] = "DevCaps1";

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,

"Device Capabilities",

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)

{

76

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), devcaps[i].szLabel, strlen(devcaps[i].szLabel)

);

TextOut(

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

);

SetTextAlign(hdc, TA_RIGHT | TA_TOP);

TextOut(

hdc, cxChar + 22 * cxCaps + 40 * cxChar, cyChar *(1 + i), szBuffer,

wsprintf(

szBuffer, "%5d",

GetDeviceCaps(hdc, devcaps[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);

}

Рис. 4.1 Программа DEVCAPS1

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