95 в двух томах Том I



Pdf просмотр
страница17/41
Дата27.11.2016
Размер4.32 Mb.
Просмотров7751
Скачиваний0
ТипРеферат
1   ...   13   14   15   16   17   18   19   20   ...   41
Рис. 4.28 Программа METAFILE
Эта программа демонстрирует использование четырех функций метафайлов, работающих с метафайлом памяти.
Первая функция — CreateMetaFile, вызванная с параметром NULL в теле обработчика сообщения WM_CREATE.
Эта функция возвращает описатель контекста устройства метафайла. Затем программа METAFILE рисует прямоугольник, две прямые и один голубой эллипс, используя данный контекст устройства метафайла. Вызовы этих 4-х функций запоминаются в двоичной форме в метафайле.
Функция
CloseMetaFile возвращает описатель метафайла. Обратите внимание, что описатель метафайла запоминается в статической переменной, поскольку он используется позднее.
Метафайл содержит двоичное представление вызовов функций GDI — одного вызова Rectangle, двух вызовов
MoveToEx, двух вызовов LineTo, вызова SelectObject (задающего голубую кисть) и вызова Ellipse. Режим отображения или преобразования не описывается координатами. Они просто запоминаются в метафайле в числовом виде.
Рис. 4.29 Вывод программы METAFILE
Во время обработки сообщения WM_PAINT программа METAFILE устанавливает режим отображения и вызывает функцию PlayMetaFile для рисования объекта в окне 100 раз. Координаты вызовов функций в метафайле интерпретируются в соответствии с режимом отображения приемного контекста устройства. Вызывая
PlayMetaFile, вы повторяете все вызовы функций, сделанные между вызовами функций CreateMetaFile и
CloseMetaFile при первоначальном создании метафайла во время обработки сообщения WM_CREATE.
Как и другие объекты GDI, метафайлы должны быть тоже удалены до завершения программы. Процедура удаления реализуется в теле обработчика сообщения WM_DESTROY с помощью функции DeleteMetaFile.
Результат работы программы METAFILE приведен на рис. 4.29.

147
Сохранение метафайлов на диске
В приведенном выше примере использование NULL в качестве параметра функции CreateMetaFile означало, что мы хотим создать метафайл в памяти. Мы можем также создать метафайл, сохраняемый на диске как обычный файл. Этот метод предпочтителен для больших метафайлов, поскольку он требует меньше памяти. Windows необходимо выделить относительно небольшой фрагмент памяти для хранения имени файла, содержащего метафайл. Однако, каждый раз, когда вы проигрываете метафайл, сохраненный на диске, будет осуществляться доступ к диску.
Для преобразования программы METAFILE для работы с дисковым метафайлом вам необходимо заменить параметр NULL в функции CreateMetaFile именем файла. По завершении обработки сообщения функцией
WM_CREATE вы можете удалить описатель метафайла с помощью функции DeleteMetaFile. Описатель удаляется, но файл на диске остается.
Во время обработки сообщения WM_PAINT вы можете получить описатель метафайла, соответствующего этому дисковому файлу, вызывая функцию GetMetaFile: hmf = GetMetaFile(szFileName);
Теперь вы можете проиграть метафайл также, как раньше. Когда обработка сообщения WM_PAINT закончится, вы можете удалить описатель метафайла:
DeleteMetaFile(hmf);
Когда придет время обработки сообщения WM_DESTROY, вам не нужно удалять метафайл, поскольку он был удален по завершении обработки сообщения WM_CREATE и в конце обработки каждого сообщения WM_PAINT.
Но вам следует удалить дисковый файл (конечно, в том случае, если он вам более не нужен): remove(szFileName);
В главе 9 будут рассмотрены ресурсы, определяемые пользователем. Ресурсы — это обычные двоичные данные, хранящиеся в EXE-файле программы, но отдельно от обычных областей кода и данных. Метафайл тоже может быть ресурсом. Если у вас есть блок данных, содержащий метафайл, вы можете создать метафайл, используя функцию: hmf = SetMetaFileBitsEx(iSize, pData);
Функция SetMetaFileBitsEx имеет парную функцию GetMetaFileBitsEx, которая копирует содержимое метафайла в блок памяти.
Расширенные метафайлы
С устаревшими (но еще поддерживаемыми) метафайлами, рассмотренными выше, связаны некоторые проблемы. В частности, программа, использующая метафайл, созданный другой программой, не может легко определить размер отображаемого образа, представляемого метафайлом. Ей нужно просмотреть метафайл и проанализировать все команды рисования. Это большая проблема.
Ранее Microsoft рекомендовала создавать метафайлы, не содержащие вызовов функции SetMapMode и других функций, изменяющих преобразование окно/область вывода. Соблюдение данной рекомендации делает метафайлы зависимыми от устройства и не дает возможности приложению изменить размер выводимого изображения. Таким образом, все координаты в метафайле — просто числа, не связанные с какой-либо системой координат.
Как мы увидим в главе 16, метафайлы устаревшего типа не передаются через буфер обмена непосредственно.
Вместо этого, буфер обмена работает с неким объектом под названием "картина метафайла" (metafile picture). Это структура типа METAFILEPICT. Описатель метафайла является полем этой структуры. Кроме того, в этой структуре также содержатся идентификатор режима отображения (отражающий единицы измерения по осям координат для всех функций GDI, содержащихся в метафайле) и размеры изображения. Эта информация помогает программе, импортирующей метафайл, установить соответствующую среду GDI для отображения образа.
Структура картины метафайла — настоящая находка. Ее, очевидно, добавили в GDI для устранения недостатков формата метафайла. Следует отметить, что аналогичная возможность не была разработана для дисковых метафайлов, и именно поэтому вам не удавалось увидеть большинство из этих файлов, используемых для обмена картинками. Они просто очень сложны для использования.
Делаем это лучше
Также как и Windows NT, Windows 95 поддерживает новый формат "расширенного метафайла". Кроме того добавляются несколько новых функций, несколько новых структур данных, новый формат буфера обмена и новое расширение файла — EMF.

148
Главное усовершенствование состоит в том, что новый формат метафайла содержит более обширный информационный заголовок, доступный посредством вызова функций. Эта информация призвана помочь приложениям выводить изображения, содержащиеся в метафайлах.
Некоторые из расширенных функций работы с метафайлами позволяют вам преобразовывать метафайлы из нового расширенного формата .EMF в устаревший формат .WMF и обратно. Конечно, это преобразование не может быть произведено без потерь. Устаревший формат метафайлов не поддерживает некоторые из новых графических возможностей (например, пути).
Базовая процедура
На рис. 4.30 приведена программа EMF1, которая создает и выводит на экран расширенный метафайл.
EMF1.MAK
#--------------------
# EMF1.MAK make file
#-------------------- emf1.exe : emf1.obj
$(LINKER) $(GUIFLAGS) -OUT:emf1.exe emf1.obj $(GUILIBS) emf1.obj : emf1.c
$(CC) $(CFLAGS) emf1.c
EMF1.C
/*-------------------------------------
EMF1.C -- Enhanced Metafile Demo #1
(c) Charles Petzold, 1996
-------------------------------------*/
#include
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{ static char szAppName[] = "EMF1";
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, "Enhanced Metafile Demo #1",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);

149
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 HENHMETAFILE hemf;
HDC hdc, hdcEMF;
PAINTSTRUCT ps;
RECT rect; switch(iMsg)
{ case WM_CREATE: hdcEMF = CreateEnhMetaFile(NULL, NULL, NULL, NULL);
Rectangle(hdcEMF, 100, 100, 200, 200);
MoveToEx (hdcEMF, 100, 100, NULL);
LineTo (hdcEMF, 200, 200);
MoveToEx (hdcEMF, 200, 100, NULL);
LineTo (hdcEMF, 100, 200); hemf = CloseEnhMetaFile(hdcEMF); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect); rect.left = rect.right / 4; rect.right = 3 * rect.right / 4; rect.top = rect.bottom / 4; rect.bottom = 3 * rect.bottom / 4;
PlayEnhMetaFile(hdc, hemf, &rect);
EndPaint(hwnd, &ps); return 0; case WM_DESTROY:
DeleteEnhMetaFile(hemf);
PostQuitMessage(0); return 0;
} return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
Рис. 4.30 Программа EMF1
В процессе обработки сообщения WM_CREATE в оконной процедуре программы EMF1, с помощью функции
CreateEnhMetaFile создается расширенный метафайл. Эта функция требует задания четырех параметров, но вы можете задать их все равными NULL. (Как удобно!) Позднее будет рассказано, как использовать эту функцию с параметрами, отличными от NULL.

150
Так же, как и функция CreateMetaFile, функция CreateEnhMetaFile возвращает описатель специального контекста устройства. Программа использует этот описатель для рисования прямоугольника и двух прямых, соединяющих противоположные углы прямоугольника. Эти вызовы функций конвертируются в двоичный вид и запоминаются в метафайле.
Наконец, вызов функции CloseEnhMetaFile завершает формирование расширенного метафайла и возвращает его описатель. Он запоминается в статической переменной типа HENHMETAFILE.
В процессе обработки сообщения WM_PAINT программа EMF1 получает размеры рабочей области окна и записывает их в структуру типа RECT. Четыре поля этой структуры пересчитываются таким образом, что прямоугольник приобретает ширину, равную половине ширины рабочей области, и высоту, равную половине высоты рабочей области, а весь прямоугольник располагается в центре рабочей области. Затем программа EMF1 вызывает функцию PlayEnhMetaFile. Первый параметр этой функции — описатель контекста устройства окна, второй — описатель расширенного метафайла, третий параметр — указатель на структуру типа RECT.
Здесь произойдет то, что происходило при создании метафайла — GDI вычислит размеры изображения, хранящегося в метафайле. В нашем случае изображение имеет ширину и высоту 100 единиц. При отображении метафайла GDI растягивает изображение так, чтобы полностью занять указанный в вызове функции
PlayEnhMetaFile прямоугольник. Три примера работы программы EMF1 в среде Windows 95 показаны на рис. 4.31.
Наконец, при обработке сообщения WM_DESTROY программа EMF1 удаляет метафайл, вызывая функцию
DeleteEnhMetaFile.
Давайте обратим внимание на некоторые вещи, которым мы могли бы научиться из программы EMF1.
Во-первых, в этой конкретной программе координаты, используемые функциями рисования прямоугольника и линий для создания расширенного метафайла, на самом деле определяют далеко не все. Вы можете удвоить их значения или вычесть константу из них — результат останется таким же. Таким образом, можно сделать вывод, что координаты имеют взаимосвязи друг с другом в определении образа.
Во-вторых, изображение растягивается так, чтобы занять весь прямоугольник, передаваемый как параметр в функцию PlayEnhMetaFile. Следовательно, как показано на рис. 4.31, изображение может быть искажено. При задании координат в метафайле предполагается, что изображение — квадрат, но в общем случае мы его не получим.
Рис. 4.31 Окна программ EMF1.
Иногда это как раз то, что требуется. В программах обработки текстов пользователю может быть предоставлена возможность задавать прямоугольник для изображения так, чтобы все изображение целиком занимало указанную область без потерь места. Пусть пользователь устанавливает правильный относительный размер, изменяя соответствующим образом размеры прямоугольника.
Однако, существуют случаи, когда нужно другое. Можно установить относительный размер исходного изображения, поскольку это бывает крайне важно для визуального представления информации. Например, эскиз лица подозреваемого в преступлении (полицейский фоторобот) не должен быть искажен относительно оригинала.
Или можно сохранить метрические размеры исходного изображения, так как важно то, что образ имеет высоту два дюйма, и не должен изображаться иначе.

151
Заглянем внутрь
Программа EMF2, приведенная на рис. 4.32, строит дисковый метафайл.
EMF2.MAK
#--------------------
# EMF2.MAK make file
#-------------------- emf2.exe : emf2.obj
$(LINKER) $(GUIFLAGS) -OUT:emf2.exe emf2.obj $(GUILIBS) emf2.obj : emf2.c
$(CC) $(CFLAGS) emf2.c
EMF2.C
/*-------------------------------------
EMF2.C -- Enhanced Metafile Demo #2
(c) Charles Petzold, 1996
-------------------------------------*/
#include
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{ static char szAppName[] = "EMF2";
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, "Enhanced Metafile Demo #2",
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;
}

152
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc, hdcEMF;
HENHMETAFILE hemf;
PAINTSTRUCT ps;
RECT rect; switch(iMsg)
{ case WM_CREATE: hdcEMF = CreateEnhMetaFile(NULL, "emf2.emf", NULL,
"EMF2\0EMF Demo #2\0");
Rectangle(hdcEMF, 100, 100, 200, 200);
MoveToEx (hdcEMF, 100, 100, NULL);
LineTo (hdcEMF, 200, 200);
MoveToEx (hdcEMF, 200, 100, NULL);
LineTo (hdcEMF, 100, 200); hemf = CloseEnhMetaFile(hdcEMF);
DeleteEnhMetaFile(hemf); return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect); rect.left = rect.right / 4; rect.right = 3 * rect.right / 4; rect.top = rect.bottom / 4; rect.bottom = 3 * rect.bottom / 4; hemf = GetEnhMetaFile("emf2.emf");
PlayEnhMetaFile(hdc, hemf, &rect);
DeleteEnhMetaFile(hemf);
EndPaint(hwnd, &ps); return 0; case WM_DESTROY:
PostQuitMessage(0); return 0;
} return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
Рис. 4.32 Программа EMF2
Обратите внимание, что первый параметр функции CreateEnhMetaFile — это описатель контекста устройства. GDI использует этот параметр для вставки метрической информации в заголовок метафайла. Если этот параметр установлен в NULL, то GDI берет эту метрическую информацию из контекста устройства дисплея.
Второй параметр функции CreateEnhMetaFile — это имя файла. Если вы установите этот параметр в NULL (как в программе EMF1), то функция построит метафайл в памяти. Программа EMF2 строит дисковый метафайл с именем EMF2.EMF.
Третий параметр функции — адрес структуры типа RECT, описывающей общие размеры метафайла. Эта часть важнейшей информации (та, что отсутствовала в предыдущем формате метафайлов Windows) заносится в заголовок метафайла. Если вы установите этот параметр в NULL, то GDI определит размеры за вас. Приятно, что

153 операционная система делает это для нас, поэтому имеет смысл устанавливать этот параметр в NULL. Если производительность вашего приложения критична, то вы можете использовать этот параметр для того, чтобы избежать лишней работы GDI.
Наконец, последний параметр — текстовая строка, описывающая метафайл. Эта строка делится на две части:
Первая часть — имя приложения (не обязательно имя программы), за которым следует NULL-символ. Вторая часть описывает визуальный образ. Эта часть завершается двумя NULL-символами. Например, используя нотацию языка C ‘\0’ для NULL-символа, можно получить строку описания следующего вида "HemiDemiSemiCad
V6.4\0Flying Frogs\0\0". Поскольку C обычно помещает NULL-символ в конец строки, заданной в кавычках, вам нужен только один символ ‘\0’ в конце строки, как показано в программе EMF2.
После создания метафайла программа EMF2 работает также, как программа EMF1, вызывая несколько функций
GDI и используя описатель контекста устройства, возвращенный функцией CreateEnhMetaFile. Эти функции рисуют прямоугольник и две линии, соединяющие его противоположные вершины. Затем программа вызывает функцию CloseEnhMetaFile для уничтожения описателя контекста устройства и получения описателя сформированного метафайла.
Затем, еще при обработке сообщения WM_CREATE, программа EMF2 делает то, чего не делала программа EMF1: сразу после получения описателя метафайла программа вызывает функцию DeleteEnhMetaFile. Этот вызов освобождает все ресурсы памяти, необходимые для построения метафайла. Однако дисковый метафайл сохраняется.
(Если вы когда-нибудь захотите избавиться от этого файла, то используйте обычные функции удаления файлов.)
Обратите внимание, что описатель метафайла не запоминается в статической переменной, как в программе EMF1, поскольку не требуется его сохранение в промежутке времени между обработкой различных сообщений.
Теперь, для использования созданного метафайла программе EMF2 необходимо получить доступ к дисковому файлу. Она делает это при обработке сообщения WM_PAINT путем вызова функции GetEnhMetaFile.
Единственный параметр этой функции — имя метафайла. Функция возвращает описатель метафайла. Программа
EMF2 передает этот описатель в функцию PlayEnhMetaFile, так же как программа EMF1. Изображение из метафайла выводится в прямоугольник, заданный последним параметром функции. Но в отличие от программы
EMF1, программа EMF2 удаляет метафайл перед завершением обработки сообщения WM_PAINT. При обработке последующих сообщений WM_PAINT программа EMF2 опять получает метафайл, проигрывает его и потом удаляет.
Запомните, что удаление метафайла влечет за собой удаление только ресурсов памяти, требуемых для построения метафайла. Дисковый метафайл сохраняется даже после завершения программы.
Поскольку программа EMF2 оставляет не удаленным дисковый метафайл, вы можете взглянуть на него. Он состоит из записей переменной длины, описываемых структурой ENHMETARECORD, определенной в заголовочных файлах Windows. Расширенный метафайл всегда начинается с заголовка типа структуры
ENHMETAHEADER.
Вам не нужен доступ к физическому дисковому метафайлу для получения заголовочной информации. Если у вас есть описатель метафайла, то вы можете использовать функцию GetEnhMetaFileHeader:
GetEnhMetaFileHeader(hemf, cbSize, &emh);
Первый параметр — описатель метафайла. Последний — указатель на структуру типа ENHMETAHEADER, а второй — размер этой структуры. Вы можете использовать функцию GetEnhMetaFileDescription для получения строки описания. Поле rclBounds структуры ENHMETAHEADER — структура прямоугольника, хранящая размеры изображения в пикселях. Поле rclFrame структуры ENHMETAHEADER — структура прямоугольника, хранящая размеры изображения в других единицах (0.01 мм).
Заголовочная запись завершается двумя структурами типа SIZE, содержащими два 32-разрядных поля, szlDevice и
szlMillimeters. Поле szlDevice хранит размеры устройства вывода в пикселях, а поле szlMillimeters хранит размеры устройства вывода в миллиметрах. Эти данные основываются на контексте устройства, описатель которого передается в функцию CreateEnhMetaFile первым параметром. Если этот параметр равен NULL, то GDI использует экран дисплея. GDI получает метрические данные с помощью функции GetDeviceCaps.
Вывод точных изображений
Большой плюс изображений, хранящихся в виде метафайлов, состоит в том, что они могут растягиваться до любого размера и при этом оставаться правильными. Увеличение или сжатие изображения — это просто масштабирование всех координатных точек, определяющих примитивы. С другой стороны, битовые образы могут терять правильность изображения при сжатии в результате отбрасывания целых строк или столбцов пикселей.
Иногда, однако, произвольное масштабирование метафайла — не очень хорошая идея. Может оказаться смешным растягивание содержащегося в метафайле образа, в виде лица человека, в толстое или тонкое лицо. В этом случае

154 надо знать правильный относительный размер образа. Некоторые изображения метафайлов могут иметь смысл только при конкретных физических размерах.
Как мы уже видели, последний параметр функции PlayEnhMetaFile — структура типа RECT, сообщающая GDI, где вы хотите нарисовать изображение в приемном контексте устройства. GDI растягивает образ так, чтобы он занял полностью указанный прямоугольник. Точный вывод изображений метафайлов — в заданных метрических размерах или с соответствующим относительным размером, требует использования информации о размерах из заголовка метафайла и точной установки размеров прямоугольника.
Это кажется достаточно сложным, но еще неизвестно, что может получиться при выводе изображения на принтер.
Поэтому эту работу отложим до главы 15.
Текст и шрифты
Первая задача, которую мы решали в этой книге, используя программирование под Windows, была задача отображения простой строки текста в центре окна. В предыдущей главе мы пошли дальше и рассмотрели отображение на экране текста, состоящего из нескольких строк, и его прокрутку в окне. Теперь наступило время рассмотреть механизм отображения текста на экране более детально. Обсуждение задач, связанных с текстом, будет продолжено также в следующих главах. В главе 11 мы увидим, как использование библиотеки диалоговых окон общего пользования (Common Dialog Box library) значительно упрощает программы, давая пользователю возможность выбирать шрифты. В главе 15 мы исследуем проблемы отображения текста на экране в таком же виде, как на бумаге.
Вывод простого текста
Давайте сначала рассмотрим существующие в Windows для вывода текста различные функции, атрибуты контекста устройства, которые определяют вид текста, а также использование стандартных (stock) шрифтов.
Наиболее часто используемой функцией вывода текста является функция, которая использовалась в программе
SYSMETS в главе 3:
TextOut(hdc, xStart, yStart, pString, iCount);
Параметры xStart и yStart определяют начальную позицию строки в логических координатах. Обычно это точка, в которую Windows помещает верхний левый угол первого символа. TextOut требует также в качестве параметра дальний указатель на символьную строку и длину строки. Эта функция не распознает текстовые строки по NULL символу.
Смысл параметров xStart и yStart функции TextOut может быть изменен с помощью функции SetTextAlign. Флаги
TA_LEFT, TA_RIGHT и TA_CENTER влияют на использование xStart при позиционировании строки по горизонтали. По умолчанию установлен флаг TA_LEFT. Если вы установите флаг TA_RIGHT при вызове функции
SetTextAlign, то последующие вызовы функции TextOut устанавливают правую границу последнего символа строки в xStart. При заданном флаге TA_CENTER в xStart устанавливается середина строки.
Аналогично, флаги TA_TOP, TA_BOTTOM и TA_BASELINE влияют на вертикальное позиционирование строки.
По умолчанию установлен флаг TA_TOP, который означает, что строка позиционируется таким образом, что yStart определяет вершину символов в строке. Использование флага TA_BOTTOM означает, что строка позиционируется над yStart. Вы можете использовать флаг TA_BASELINE для размещения строки таким образом, чтобы положение базовой линии определялось значением yStart. Базовая линия — это линия, ниже которой располагаются "хвостики" некоторых строчных букв (например, р, q, у).
Если вы вызываете SetTextAlign с флагом TA_UPDATECP, Windows игнорирует параметры xStart и yStart функции
TextOut и вместо них использует текущее положение пера, ранее установленное функциями MoveToEx, LineTo или какой-либо другой функцией, изменяющей текущее положение пера. Флаг TA_UPDATECP также заставляет функцию TextOut изменить значение текущего положения пера на конец строки (при установленном флаге
TA_LEFT) или на начало строки (при установленном флаге TA_RIGHT). Это используется для отображения строки текста с помощью последовательных вызовов функции TextOut. Когда горизонтальное позиционирование осуществляется при установленном флаге TA_CENTER, текущее положение пера не меняется после вызова функции TextOut.
Теперь давайте вспомним, как осуществлялся вывод на экран текста в виде столбцов в ряде программ SYSMETS в главе 3. Тогда каждый новый вызов функции TextOut использовался для отображения на экране одного столбца. В качестве альтернативы можно использовать функцию TabbedTextOut

:
TabbedTextOut(hdc, xStart, yStart, pString, iCount, iNumTabs, piTabStops, xTabOrigin);

155
Если строка символов содержит символы табуляции (‘\t’ или 0х09), то функция TabbedTextOut будет при выводе заменять символы табуляции числом пробелов, соответствующих списку целых параметров, которые вы передаете в функцию.
Первые пять параметров функции TabbedTextOut такие же, как у функции TextOut. Шестой параметр — число позиций табуляции, седьмой параметр — массив позиций табуляции, заданных в пикселях. Например, если средняя ширина символа 8 пикселей, и вы хотите установить позиции табуляции через каждые 5 символов, то этот список будет содержать числа 40, 80, 120 и т. д., в порядке возрастания.
Если шестой и седьмой параметры имеют значения 0 или NULL, то позиции табуляции устанавливаются через равные промежутки, равные восьмикратной средней ширине символов. Если шестой параметр равен 1, то седьмой параметр указывает на простое целое, которое каждый раз прибавляется для определения следующей позиции табуляции. (Например, если шестой параметр равен 1, а седьмой параметр является указателем на переменную, содержащую число 30, то позиции табуляции будут установлены так: 30, 60, 90, ... пикселей.) Последний параметр задает логическую координату по горизонтали точки отсчета позиций табуляции. Точка отсчета может совпадать с начальной позицией строки или отличаться от нее.
Примером другой расширенной функции вывода текста является функция ExtTextOut (приставка Ext означает расширенная):
ExtTextOut(hdc, xStart, yStart, iOptions, &rect, pString, iCount, pxDistance);
Пятый параметр этой функции является указателем на прямоугольную структуру. Эта структура является прямоугольником отсечения (если параметр iOptions имеет значение ETO_CLIPPED) или прямоугольником фона, который должен быть закрашен текущим цветом фона (если параметр iOptions имеет значение ETO_OPAQUE). Вы можете задавать обе опции или ни одной.
Последний параметр является массивом целых величин, задающих интервалы между соседними символами строки. Это позволяет программно сжимать или растягивать межсимвольный интервал, что иногда требуется для того, чтобы разместить отдельное слово в узком столбце. Если этот параметр имеет значение NULL, то устанавливается значение межсимвольного интервала по умолчанию.
Одной из функций вывода текста более высокого уровня является функция DrawText, которую мы использовали в программе HELLOWIN в главе 2. Вместо указания координат начальной позиции вы задаете структуру типа RECT, определяющую прямоугольник, в котором вы хотите разместить текст:
DrawText(hdc, pString, iCount, &rect, iFormat);
Так же, как и другие функции вывода текста, функция DrawText требует задания в качестве параметров дальнего указателя на символьную строку и длину строки. Однако, при использовании функции DrawText для вывода строки, оканчивающейся символом NULL, вы можете задать значение параметра iCount равным —1. В этом случае
Windows вычислит длину строки.
Если параметр iFormat имеет значение 0, то Windows интерпретирует текст как ряд строк, разделенных символами возврата каретки (‘\r’ или 0х0D) или символами конца строки (‘\n’ или 0х0А). Вывод текста производится, начиная с верхнего левого угла прямоугольника. Возврат каретки или конец строки интерпретируется как символ "новая строка" (newline). В соответствии с этим Windows прерывает вывод текущей строки и начинает новую строку.
Вывод новой строки начинается под предыдущей строкой от левого края прямоугольника с интервалом равным высоте символа в строке (без учета величины пространства, заданного в шрифте в качестве межстрочного интервала (external leading)). Любой текст, в том числе и части букв, которые при отображении на экране попадают правее или ниже границ прямоугольника, отсекаются.
Вы можете изменить действие функции DrawText по умолчанию, задав значение параметра iFormat, как комбинацию одного или нескольких флагов. Флаг DT_LEFT (установлен по умолчанию) задает выравнивание выводимого текста влево, флаг DT_RIGHT — выравнивание вправо, флаг DT_CENTER — выравнивание по центру относительно левой и правой сторон прямоугольника. Поскольку флаг DT_LEFT имеет значение 0, вы можете не задавать его значение в явном виде, если хотите, чтобы весь выводимый текст был выровнен влево.
Если вы не хотите, чтобы символы возврата каретки и символы конца строки интерпретировались как символы начала новой строки, вы можете включить идентификатор DT_SINGLELINE. В этом случае Windows интерпретирует символы возврата каретки и конца строки как отображаемые символы, а не как управляющие символы. Если вы используете идентификатор DT_SINGLELINE, вам необходимо также задать положение строки по вертикали: вверху прямоугольника (флаг DT_TOP, включен по умолчанию), внизу прямоугольника (флаг
DT_BOTTOM) или посередине между верхней и нижней границами прямоугольника вывода (флаг
DT_VCENTER).
Когда на экран выводится текст, состоящий из нескольких строк, Windows в обычном режиме заканчивает строки, только встретив символ возврата каретки или символ конца строки. Однако, если строка оказывается длиннее, чем ширина прямоугольника вывода, вы можете использовать флаг DT_WORDBREAK. В этом случае Windows будет

156 обрывать строки в конце слов внутри строки. При выводе любого текста (состоящего из одной строки или многострочного) Windows отсекает ту часть текста, которая попадает за пределы прямоугольника вывода. Вы можете избежать этой ситуации, включив флаг DT_NOCLIP, который также ускоряет выполнение функции. Когда
Windows осуществляет вывод на экран текста, состоящего из нескольких строк, то межстрочный интервал обычно выбирается равным высоте символа без учета величины пространства, заданного в шрифте, как межстрочный интервал. Если вы хотите, чтобы величина этого пространства была включена в межстрочный интервал, то вы можете использовать флаг DT_EXTERNALLEADING.
Если текст содержит символы табуляции (‘\t’ или 0х09), вам необходимо включить флаг DT_EXPANDTABS. По умолчанию позиции табуляции установлены через каждые восемь символьных позиций. Вы можете задать разные позиции табуляции, используя флаг DT_TABSTOP. В этом случае старший байт параметра iFormat содержит число символьных позиций для каждой новой позиции табуляции. Однако, здесь рекомендуется избегать использования флага DT_TABSTOP, поскольку старший байт параметра iFormat используется также для некоторых других флагов.



Поделитесь с Вашими друзьями:
1   ...   13   14   15   16   17   18   19   20   ...   41


База данных защищена авторским правом ©nethash.ru 2019
обратиться к администрации

войти | регистрация
    Главная страница


загрузить материал