Текст книги "Программирование в Delphi. Трюки и эффекты"
Автор книги: Александр Чиртик
Жанр: Программирование, Компьютеры
сообщить о неприемлемом содержимом
Текущая страница: 12 (всего у книги 24 страниц)
Контекст устройства принтера может использоваться как для матричного, струйного и лазерного принтера, так и для плоттера. Приложение создает данный контекст устройства посредством вызова функции CreateDC. При этом задаются такие необходимые параметры, как имя драйвера принтера, имя принтера, файла или имени устройства для физической среды вывода и других параметров инициализации. После завершения приложением операции печати требуется вызвать функцию DeleteDC для удаления созданного контекста. Заметьте, что созданный контекст устройства принтера должен быть удален посредством именно этой функции. Освобождение с помощью функции ReleaseDC невозможно.
Точно так же, как приложению требуется контекст устройства экрана прежде, чем оно сможет осуществлять операции вывода в клиентскую область окна, так и контекст устройства принтера нужен прежде, чем можно будет осуществлять операции вывода на принтер. Контекст устройства принтера подобно контексту устройства экрана содержит информацию о графических объектах и их атрибутах, а также о графических режимах, которые воздействуют на операции вывода. Графические объекты включают карандаш (для рисования линий), кисть (для заливки) и шрифт (для вывода текста).
В отличие от контекста устройства экрана, контексты устройства принтера не связаны с компонентом управления окна Win32 API и не могут быть получены посредством вызова функции GetDC. Вместо этого приложение обязано вызвать функцию CreateDC или PrintDlgEx.
Если вы вызываете функцию CreateDC, то обязаны указать драйвер принтера и порт. Для получения этих данных можно воспользоваться функцией GetPrinter или EnumPrinters.
Контекст устройства памятиЧтобы дать приложениям возможность осуществлять операции вывода в память вместо работы с фактическим устройством, используется специальный контекст устройства для растровых операций, который называется контекстом устройства памяти. Возможность осуществлять операции вывода в памяти может понадобиться для улучшения характеристик вывода изображений. Контекст устройства памяти дает возможность системе обработать часть памяти как виртуальное устройство – массив битов в памяти, которые приложение может временно использовать для сохранения данных растрового изображения, созданного на нормальной поверхности для рисования. Поскольку точечный рисунок совместим с устройством, то иногда контекст устройства памяти упоминается как совместимый.
Контекст устройства памяти сохраняет растровые изображения для специфического устройства. Приложение может создавать данный контекст посредством вызова функции CreateCompatibleDC. Результатом ее выполнения является растровое изображение, имеющее цветной формат, совместимый с форматом первоначального устройства.
Первоначально изображение в контексте устройства памяти имеет размер 1 х 1 пиксел. Прежде чем приложение сможет начать работать с изображением, оно должно установить битовый массив с соответствующей шириной и высотой в контекст устройства с помощью функции SelectObject.
Когда приложение передает описатель, который получен с помощью функции CreateCompatibleDC, одной из функций рисования, то запрашиваемая операция вывода не осуществляется на поверхности рисунка устройства. Вместо этого система сохраняет цветовую информацию для результирующей линии, кривой, текста или региона в битовом массиве. Приложение может копировать изображение, хранящееся в памяти, обратно на поверхность рисунка посредством вызова функции BitBlt, указывая в качестве источника контекст устройства памяти, а в качестве приемника – контекст устройства окна или экрана.
Информационный контекст устройстваWin32 API поддерживает информационный контекст устройства, используемый для восстановления или получения заданных по умолчанию параметров устройства. Для создания информационного контекста приложение должно вызвать функцию CreateIC. Для получения информации об объектах, заданных по умолчанию для интересующего устройства, используются функции GetCurrentObject и GetObject. Использование информационного контекста устройства более эффективно, чем контекстов других типов, поскольку Win32 API работает с информационным контекстом на более низком уровне и не создает структуры, которые необходимы для их работы. После завершения работы приложения с информационным контекстом устройства необходимо вызвать функцию DeleteDC для удаления созданного контекста.
Графические режимы
Операционная система Windows поддерживает пять различных, позволяющих приложениям определять тип смешивания цветов, место и параметры вывода и т. д., графических режимов настроек:
• фона – определяет порядок смешивания цветов фона текстовых объектов и растровых изображений с цветом фона поля вывода;
• отображения – определяет, как происходит смешивание цвета карандашей, кистей, текстовых объектов и растровых изображений с цветом фона;
• масштабирования – определяет преобразование логических координат при графическом выводе в окна, на экран или принтер;
• заполнение контуров – определяет, каким образом будут применяться шаблоны кисти при заполнении контуров;
• сжатия – определяет, каким образом происходит преобразование цветов растровых изображений при их увеличении (уменьшении).
Работа со шрифтами
Приложение может использовать следующие технологии шрифтов для отображения и печати текста:
• растровые;
• векторные;
• TrueType;
• OpenType.
Различие между данными видами шрифтов заключается в способе хранения параметров начертания символов в специальных шрифтовых файлах. Растровые шрифты хранят каждый символ в виде растра (битового массива). Векторные шрифты хранят относительные координаты концов отрезков, из которых состоит соответствующий символ. Шрифты TrueType и OpenType содержат информацию о линиях и командах изгиба, а также настроечную информацию для точного отображения символа, которая используется при изменении масштаба отображения. Шрифты OpenType эквивалентны шрифтам TrueType, за исключением того, что они позволяют определять дополнительную информацию о символах.
Поскольку точечные рисунки для каждого символа в растровом шрифте предназначены для определенной разрешающей способности устройства, то, следовательно, качество их отображения зависит от устройства вывода. Векторные же шрифты, напротив, не зависят от устройства вывода, однако время, необходимое для их отображения, больше, чем у растровых шрифтов или шрифтов TrueType. Последние (TrueType) обеспечивают приемлемую скорость вывода и могут быть масштабированы с сохранением начального вида символов.
Операционная система Windows предоставляет разработчикам широкий набор функций для использования шрифтового оформления своих приложений, начиная с предоставления каждому контексту устройства шрифта по умолчанию и заканчивая предоставлением системного окна выбора шрифтов, которое можно использовать в приложении.
Рисование примитивов
Теперь, после того как вы немного ознакомились с теорией, пора начинать практиковаться. Далее будет создано простое приложение, позволяющее рисовать на форме ряд примитивов. Для этого в новом приложении для формы необходимо реализовать обработку события OnPaint (листинг 6.1).
Листинг 6.1. Обработчик события формы OnPaint
procedureTfmShapes.FormPaint (Sender: TObject);
var
hCurDC: HDC;
hCurPen, hOldPen: HPEN;
hCurBrush, hOldBrush: HBRUSH;
begin
//получаем общий контекст устройства
hCurDC:= GetDC(Handle);
//создаем графический объект "Каран даш"
hCurPen:= CreatePen(PS_SOLID, 2, RGB(255, 64, 0));
//выбираем его для общего контекста устройства экрана
//и запоминаем ранее выбранный
hOldPen:= SelectObject(hCurDC, hCurPen);
//создаем графический объект "Кисть"
hCurBrush:= CreateSolidBrush(RGB(0, 128, 255));
//выбираем ее для общего контекста устройства экрана
//и запоминаем ранее выбранную
hOldBrush:= SelectObject(hCurDC, hCurBrush);
//рисуем эллипс
Ellipse(hCurDC, 10, 10, 100, 70);
//рисуем прямоугольник
Rectangle(hCurDC, 110, 10, 210, 70);
//прямоугольник с округленными углами
RoundRect(hCurDC, 10, 80, 100, 140, 10, 10);
//прямоугольник в виде "бочки"
RoundRect(hCurDC, 110, 80, 210, 140, 10, 100);
//рисуем прямую
MoveToEx(hCurDC, 10, 150, nil);
LineTo(hCurDC, 100, 220);
//рисуем дугу
Arc(hCurDC, 110, 150, 210, 220, 110, 150, 210, 220);
//восстан вливаем ранее выбранную кисть
SelectObject(hCurDC, hOldBrush);
//удаляем созданную кисть
DeleteObject(hCurBrush);
//восстанавливаем ранее выбранный карандаш
SelectObject(hCurDC, hOldPen);
//удаляем созданный карандаш
DeleteObject(hCurPen);
//освобождаем общий контекст устройства
ReleaseDC(Handle, hCurDC);
end;
Прежде чем начать рисовать, необходимо получить контекст устройства формы. Для этого используется функция GetDC:
hCurDC:= GetDC(Handle);
Эта функция получает описатель контекста устройства экрана для клиентской области указанного окна или всего экрана. Функция имеет следующий формат заголовка:
Function GetDC(hWnd: HWND): HDC;
Здесь hWnd – дескриптор окна, для которого получается контекст устройства. Если это значение равно nil, то GetDC возвращает контекст устройства для всего экрана. В случае успешного выполнения задачи функция возвращает контекст устройства, в противном случае – nil.
Теперь нужно изменить атрибуты контекста устройства по умолчанию на необходимые. Для этого изменим цвет карандаша и его толщину, а также цвет кисти, предварительно создав новый графический объект с помощью функции CreatePen:
hCurPen:= CreatePen(PS_SOLID, 2, RGB(255, 64, 0));
Формат данной функции следующий:
Function CreatePen(fnPenStyle: Integer; nWidth: Integer; crColor: COLORREF): HPEN;
Параметр fnPenStyle определяет стиль карандаша. Перечень возможных значений этого параметра приведен в табл. 6.1.
Таблица 6.1. Стили карандаша
Параметр nWidth определяет ширину карандаша в логических единицах. Если nWidth равен 0, то карандаш будет иметь ширину в один пиксел независимо от текущей трансформации.
CreatePen создает карандаш с заданной шириной и стилем PS_SOLID, если вы указали ширину больше, чем 1, для одного из стилей: PS_DASH, PS_DOT, PS_ DASHDOT, PS_DASHDOTDOT.
Параметр crColor задает цвет карандаша.
Если выполнение функции CreatePen завершилось удачно, то она возвращает дескриптор логического карандаша. В противном случае она возвращает nil.
После того как карандаш создан, следует его выбрать для полученного контекста с помощью функции SelectObject.
hOldPen:= SelectObject(hCurDC, hCurPen);
Данная функция имеет следующий формат:
Function SelectObject(hdc: HDC; hgdiobj: HGDIOBJ): HGDIOBJ;
Здесь hdc – дескриптор контекста устройства, а hgdiobj – дескриптор выбираемого объекта.
Если выбранный объект не является регионом и функция выполнилась успешно, то она возвращает дескриптор на объект, который был заменен. Если же выбранный объект является регионом и функция выполнилась успешно, то она возвращает одно из приведенных в табл. 6.2 значений.
Таблица 6.2. Результат выполнения функции SelectObject для выбранного региона
Если во время выполнения функции произойдет ошибка и выбранный объект не будет являться регионом, то возвратится значение nil. В противном случае будет возвращено значение HGDI_ERROR.
Функция SelectObject возвращает предыдущий выбранный объект указанного типа. Приложение должно всегда восстанавливать объект по умолчанию, после того как закончилось рисование с использованием нового объекта.
Приложение не может выбрать битовый массив более чем для одного контекста устройства одновременно.
После выбора созданного и записи предыдущего выбранного карандашей необходимо создать и выбрать кисть. Для этого используется функция CreateSolidBrush:
hCurBrush:= CreateSolidBrush(RGB(0, 128, 255));
Данная функция имеет следующий формат:
Function CreateSolidBrush(crColor: COLORREF): HBRUSH;
Параметр crColor определяет цвет кисти.
Если функция завершилась успешно, то она возвращает дескриптор логической кисти. В противном случае она возвращает значение nil.
После создания кисти необходимо выбрать ее с использованием функции SelectObject и запомнить ранее выбранную:
hOldBrush:= SelectObject(hCurDC, hCurBrush);
Далее с использованием полученного контекста устройства с новыми графическими объектами создаются примитивы.
Чтобы нарисовать эллипс, используется функция Ellipse:
Ellipse(hCurDC, 10, 10, 100, 70);
Эта функция имеет следующий формат:
Function Ellipse(hdc: HDC; nLeftRect, nTopLeft, nRightRect, nBottomRect: Integer): BOOL;
Ее параметры имеют следующие значения:
• hdc – дескриптор контекста устройства;
• nLeftRect – задает координату x (в логических единицах) верхнего левого угла описываемого прямоугольника;
• nTopRect – задает координату y (в логических единицах) верхнего левого угла прямоугольника;
• nRightRect – задает координату x (в логических единицах) правого нижнего угла прямоугольника;
• nBottomRect – задает координату y (в логических единицах) правого нижнего угла прямоугольника.
Если выполнение функции завершается успешно, то ее результат составляет ненулевое значение. В противном случае возвращается 0.
Для рисования прямоугольника используется функция Rectangle:
Rectangle(hCurDC, 110, 10, 210, 70);
У данной функции такой же формат, как и у Ellipse, однако значения последних четырех параметров немного иные. Они задают сам прямоугольник, а не прямоугольник, описываемый вокруг эллипса.
Далее с помощью функции RoundRect создадим прямоугольник с округленными углами:
RoundRect(hCurDC, 10, 80, 100, 140, 10, 10);
У данной функции первые пять параметров аналогичны параметрам предыдущей функции, а последние два задают ширину и высоту эллипса, с помощью которого происходит округление углов прямоугольника.
Следующим создаваемым примитивом будет отрезок. Процесс его рисования осуществляется в два этапа. Сначала с помощью функции MoveToEx устанавливается начальная точка отрезка, а затем используется функция MoveTo с указанием конечной точки:
MoveToEx(hCurDC, 10, 150, nil);
LineTo(hCurDC, 100, 220);
Четвертый параметр функции MoveToEx – переменная типа TPoint, в которую помещается предыдущее положение карандаша.
Последней рисуется дуга с помощью функции Arc.
Arc(hCurDC, 110, 150, 210, 220, 110, 150, 210, 220);
В ней первые пять параметров соответствуют параметрам функции Rectangle, а последние четыре задают начальную и конечную радиальные точки дуги.
После того как все операции вывода выполнены, требуется освободить занятые ресурсы системы. Это осуществляется следующим образом:
SelectObject(hCurDC, hOldPen);
DeleteObject(hCurPen);
SelectObject(hCurDC, hOldPen);
DeleteObject(hCurPen);
ReleaseDC(Handle, hCurDC);
Сначала восстанавливаются карандаш и кисть для контекста устройства и удаляются созданные, а после освобождается и сам контекст устройства. Результат выполнения приложения показан на рис. 6.1.
Рис. 6.1. Результат работы приложения «Рисование примитивов»
На этом рисунке вы можете увидеть получаемые в результате изображения и влияние параметров функции на них.
Работа с текстом
Далее будет разработано простое приложение, которое будет способно выводить текст под различным углом через определенный интервал времени. Для этого необходимо опять выполнить обработку события OnPaint формы, в которой будет осуществляться вывод некоторого текста на поверхность формы. Исходный код данного обработчика приведен в листинге 6.2.
Листинг 6.2. Обработчик события формы OnPaint
procedure TfmText.FormPaint(Sender: TObject);
var
hCurDC: HDC;
hCurFont, hOldFont: HFONT;
nOldMode: Integer;
sText: String;
begin
//получаем общий контекст устройства
hCurDC:= GetDC(Handle);
//создаем шрифт из шаблона
hCurFont:= CreateFontIndirect(LogFontData);
//выбираем созданный шрифт
hOldFont:= SelectObject(hCurDC, hCurFont);
//устанавливаем новый режим вывода
nOldMode:= SetBkMode(hCurDC, TRANSPARENT);
//устанавливаем цвет текста
SetTextColor(hCurDC, RGB(0, 0, 255));
//задаем текстовую строку
sText:= 'Текст примера';
//выводим текст на экран
TextOut(hCurDC, Width div 2, Height div 2, PAnsiChar(sText), Length(sText));
//восстанавливаем режим вывода
SetBkMode(hCurDC, nOldMode);
//восстанавливаем ранее выбранный шрифт
SelectObject(hCurDC, hOldFont);
//удаляем созданный шрифт
DeleteObject(hCurFont);
//освобождаем общий контекст устройства
ReleaseDC(Handle, hCurDC);
end;
Как можно заметить, обработчик события OnPaint работает по той же схеме, что и в предыдущем примере. Изначально производится получение контекста устройства, затем создается необходимый графический объект, который выбирается вместо установленного по умолчанию. После этого восстанавливаются все атрибуты контекста устройства, и затем он освобождается.
Теперь перейдем от общего к частному. Логический шрифт создается на основании указанных характеристик с помощью функции CreateFontIndirect:
hCurFont:= CreateFontlndirect(LogFontData);
Данная функция имеет следующий формат заголовка:
Function CreateFontIndirect(const lf: LOGFONT): HFONT;
Здесь параметр lf содержит описание характеристик логического шрифта. Если функция завершается успешно, то она возвращает дескриптор логического шрифта. В противном случае ее результатом является значение nil.
После создания шрифта он выбирается в контексте устройства:
hOldFont:= SelectObject(hCurDC, hCurFont);
Далее необходимо установить режим прозрачности, то есть такой режим, при котором будет выводиться только текст без предварительной заливки фона определенным цветом:
nOldMode:= SetBkMode(hCurDC, TRANSPARENT);
Функция SetBkMode служит для установки режима смешивания фона определенного контекста устройства. Этот режим используется для текста, штриховых кистей, а также для карандашей, использующих стиль, отличный от сплошных линий.
Формат заголовка данной функции следующий:
Function SetBkMode(hdc: HDC; nBkMode: Integer): Integer;
Здесь параметр hdc задает описатель контекста устройства, для которого устанавливается режим смешивания фона, а nBkMode определяет режим смешивания фона и может принимать одно из значений, указанных в табл. 6.3.
Таблица 6.3. Режимы смешивания фона
Если выполнение функции производится успешно, то она возвращает предыдущий установленный режим смешивания фона. В противном случае она возвращает 0.
Стоит отметить, что данная функция оказывает эффект на стили линий, которые рисуются с использованием карандаша, созданного с помощью функции CreatePen. Если карандаш создан с помощью функции ExtCreatePen, то никакого эффекта не будет.
Параметр nBkMode может быть установлен и в другие значения, отличные от указанных, которые специфичны для данного драйвера устройства. GDI передает драйверу устройства полученное специфическое значение.
Теперь необходимо установить определенный цвет текста с помощью функции SetTextColor для контекста устройства:
SetTextColor(hCurDC, RGB(0, 0, 255));
Данная функция имеет следующий формат заголовка:
Function SetTextColor(hdc: HDC; crColor: COLORREF): COLORREF;
Первый параметр функции задает контекст устройства, для которого устанавливается цвет текста. Второй параметр задает сам цвет, который необходимо установить. В результате функция возвращает предыдущий установленный цвет, но если она завершается неудачно, то возвращается CLR_INVALID.
Цвет текста используется при рисовании изображения каждого символа с помощью функций TextOut и ExtTextOut, а также для преобразования растрового изображения при конвертировании из цветного в монохромный режим.
На этом все необходимые подготовки к выводу текста можно считать завершенными, и теперь необходимо просто вывести его с центра формы:
TextOut(hCurDC, Width div 2, Height div 2, PAnsiChar(sText), Length(sText));
Однако обработать лишь событие OnPaint недостаточно, поэтому на форму необходимо поместить таймер и установить интервал его срабатывания равным, например, 100, а затем в обработчике изменять атрибуты текста, которые задают угол его наклона при выводе. После этого нужно заставить срабатывать обработчик события OnPaint формы посредством вызова функции RePaint (листинг 6.3).
Листинг 6.3. Обработчик события таймера OnTimer
procedure TfmText.TurnTimerTimer(Sender: TObject);
begin
with LogFontData do
begin
lfEscapement:= lfEscapement + 60;
lfOrientation:= lfEscapement;
end;
RePaint;
end;
Переменная LogFontData объявлена следующим образом:
LogFontData: LOGFONT;
На основании ее создается шрифт, которым выводится текст. Здесь изменяются только два ее поля, которые влияют на наклон текста при выводе. Все остальные параметры только единожды заполняются при создании формы. Там же активизируется и таймер (листинг 6.4).
Листинг 6.4. Обработчик события формы OnCreate
procedure TfmText.FormCreate(Sender: TObject);
begin
with LogFontData do
begin
lfHeight:= 30; //высота шрифта
lfWidth:= 0; //средняя ширина символа
lfEscapement:= 0; //наклон строки относительно оси oX
lfOrient ati on:= 0; //наклон символа относительно оси oX
lfWeight:= FW_BOLD; //вес сшрифта
lfItalic:= 0;
lfUnderline:= 0;
lfStrikeOut:= 0;
lfCharSet:= DEFAULT_CHARSET; //кодовая страница по умолчанию
lfOut Precision:= OUT_DEFAULT_PRECIS; //точность вывода
lfClip Precision:= CLIP_DEFAULT_PRECIS; //отсечение вывода
lfQu alit y:= PROOF_QU ALITY; //качество вывода
lfPit chAndFamily:= VARIABLE_PITCH or FF_DONTCARE; //семейство
//шрифта
lfFaceName:= 'Arial'; //название шрифта
end;
TurnTimer.Enabled:= True;
end;
Результат работы приложения показан на рис. 6.2
Рис. 6.2. Результат работы приложения «Работа с текстом»
Правообладателям!
Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.