Текст книги "Delphi. Трюки и эффекты"
Автор книги: Александр Чиртик
Жанр: Программирование, Компьютеры
сообщить о неприемлемом содержимом
Текущая страница: 12 (всего у книги 24 страниц)
Контекст устройства принтера может использоваться одинаково как для матричного, струйного и лазерного принтера, так и для плоттера. Приложение создает данный контекст устройства посредством вызова функции CreateDC. При этом задаются такие необходимые параметры, как имя драйвера принтера, имя принтера, файла или имени устройства для физической среды вывода и других параметров инициализации. Когда приложение завершает операцию печати, то требуется вызвать функцию DeleteDC для удаления созданного контекста. Заметьте, что созданный контекст устройства принтера должен быть удален посредством именно этой функции. Освобождение с помощью функции ReleaseDC невозможно.
Точно так же, как приложению требуется контекст устройства экрана прежде, чем оно сможет осуществлять операции вывода в клиентскую область окна, нужен контекст устройства принтера прежде, чем можно будет осуществлять операции вывода на принтер. Контекст устройства принтера, подобно контексту устройства экрана, содержит информацию о графических объектах и их атрибутах, а также о графических режимах, которые воздействуют на операции вывода. Графические объекты включают карандаш (для рисования линий), кисть (для заливки) и шрифт (для вывода текста).
В отличие от контекста устройства экрана, контексты устройства принтера не связаны с компонентом управления окна Win32 API и не могут быть получены посредством вызова функции GetDC. Вместо этого приложение обязано вызвать одну из функций: CreateDC или PrintDlgEx.
Если вы вызываете функцию CreateDC, то обязаны указать драйвер принтера и порт. Для получения этих данных можно воспользоваться одной из функций: GetPrinter или EnumPrinters.
Контекст устройства памятиЧтобы дать возможность приложениям осуществлять операции вывода в память вместо работы с фактическим устройством, используется специальный контекст устройства для растровых операций, который называется контекстом устройства памяти. Возможность осуществлять операции вывода в памяти может понадобиться для улучшения характеристик вывода изображений. Контекст устройства памяти дает возможность системе обработать часть памяти как виртуальное устройство. Это массив битов в памяти, которые приложение может временно использовать для сохранения данных растрового изображения, созданного на нормальной поверхности для рисования. Поскольку точечный рисунок совместим с устройством, то иногда контекст устройства памяти упоминается как совместимый.
Контекст устройства памяти сохраняет растровые изображения для специфического устройства. Приложение может создать данный контекст посредством вызова функции CreateCompatibleDC. Результатом ее выполнения является растровое изображение, имеющее цветной формат, совместимый с форматом первоначального устройства.
Первоначально изображение в контексте устройства памяти имеет размер 1x1 пиксел. Прежде чем приложение сможет начать работать с изображением, оно должно установить битовый массив с соответствующей шириной и высотой в контекст устройства, вызывая функцию SelectOb j ect.
Когда приложение передает описатель, который получен при помощи функции CreateCompatibleDC (одной из функций рисования), то запрашиваемая операция вывода не осуществляется на поверхности рисунка устройства. Вместо этого система сохраняет цветовую информацию для результирующей линии, кривой, текста или региона в битовом массиве. Приложение может копировать изображение, хранящееся в памяти, обратно на поверхность рисунка посредством вызова функции BitBlt, указывая в качестве источника контекст устройства памяти, а в качестве приемника – контекст устройства окна или экрана.
Информационный контекст устройстваWin32 API поддерживает информационный контекст устройства, используемый, чтобы восстановить или получить заданные по умолчанию параметры устройства. Для создания информационного контекста приложение должно вызвать функцию CreatelC. Для получения информации об объектах, заданных по умолчанию для интересующего устройства, используются функции GetCurrentOb j ect и GetObject. Использование информационного контекста устройства более эффективно, чем контекстов других типов, потому как Win32 API работает с информационным контекстом на более низком уровне и не создает структур, необходимых для их работы. После завершения работы приложения с информационным контекстом устройства необходимо вызвать функцию DeleteDC для удаления созданного контекста.
6.4. Графические режимы
Операционная система Windows поддерживает пять различных графических режимов, которые позволяют приложениям определять тип смешивания цветов, место и параметры вывода и т. д.:
• настройки фона – определяет, как происходит смешивание цветов фона текстовых объектов и растровых изображений с цветом фона поля вывода;
• отображения – определяет, как происходит смешивание цвета карандашей, кистей, текстовых объектов и растровых изображений с цветом фона;
• масштабирования – определяет преобразование логических координат при графическом выводе в окна, на экран или принтер;
• заполнение контуров – определяет, каким образом будут применяться шаблоны кисти при заполнении контуров;
• сжатия – определяет, каким образом происходит преобразование цветов растровых изображений при их увеличении (уменьшении).
6.5. Работа со шрифтами
Приложение может использовать четыре различных вида технологий шрифта для отображения и печати текста:
• растровые;
• векторные;
• TrueType;
• ОрепТуре.
Отличие между данными видами шрифтов заключается в способе хранения параметров начертания символов в специальных шрифтовых файлах. В случае растровых шрифтов каждый символ хранится в виде растра (битового массива). Векторные шрифты хранят для каждого символа относительные координаты концов отрезков, из которых состоит соответствующий символ. Шрифты TrueType и ОрепТуре содержат информацию о линиях и командах изгиба, а также настроечную информацию для точного отображения символа, которая используется при уменьшении и увеличении масштаба отображения. Шрифты ОрепТуре эквивалентны шрифтам TrueType, за исключением того, что они позволяют определять дополнительную информацию о символах.
Поскольку точечные рисунки для каждого символа в растровом шрифте предназначены для определенной разрешающей способности устройства, то, следовательно, качество их отображения зависит от устройства вывода. Напротив, векторные шрифты не зависят от устройства вывода, однако время, необходимое для их отображения, больше, чем у растровых или шрифтов TrueType. Последние обеспечивают приемлемую скорость вывода и могут быть промасштабированы с сохранением изначального вида символов.
Операционная система Windows предоставляет разработчикам широкий набор функций для использования шрифтового оформления своих приложений, начиная с того, что каждый контекст устройства имеет шрифт по умолчанию, и заканчивая предоставлением системного диалога для выбора шрифтов, который можно использовать в приложении.
6.6. Рисование примитивов
Теперь вы знаете хотя бы минимум теории, поэтому пора начинать практиковаться. Создадим простое приложение, которое будет рисовать на форме ряд примитивов. Для этого в новом приложении для формы сделаем обработку события OnPaint (листинг 6.1).
Листинг 6.1. Обработчик события формы OnPaint
procedure TfmShapes.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;
Параметр f nPenStyle задает стиль карандаша. Возможные значения этого параметра приведены в табл. 6.1.
Таблица 6.1. Стили карандаша
Параметр nWidth задает ширину карандаша в логических единицах. EonnnWidth равен 0, то карандаш будет шириной в один пиксел независимо от текущей трансформации.
CreatePen возвращает карандаш с заданной шириной со стилем PSSOLID, если вы указали ширину больше, чем 1, для одного из стилей: PS_DASH, PS_DOT, PSJDASHDOT, PS_DASHDOTDOT.
Параметр crColor задает цвет карандаша.
Если функция завершилась удачно, то она возвращает дескриптор логического карандаша. В противном случае она возвращает nil.
После того как карандаш создан, следует его выбрать для полученного контекста при помощи функции SelectObject:
hOldPen:= SelectObject(hCurDC, hCurPen);
Данная функция имеет следующий формат:
Function SelectObject(hdc: HDC; hgdiobj: HGDIOBJ): HGDIOBJ;
• hdc – дескриптор контекста устройства;
• hgdiobj – дескриптор на выбираемый объект.
Если выбранный объект не регион и функция выполнилась успешно, то она возвращает дескриптор на объект, который был заменен. Если выбранный объект регион и функция выполнилась успешно, то возвращаемое значение может быть одним из приведенных в табл. 6.2.
Таблица 6.2. Результат SelectObject для выбранного объекта регион
Если происходит ошибка и выбранный объект не регион, то возвращаемое значение – nil. Иначе – HGDI_ERROR.
Функция возвращает предыдущий выбранный объект указанного типа. Приложение должно всегда восстанавливать объект по умолчанию после того, как закончилось рисование с использованием нового объекта.
Приложение не может выбрать битовый массив более чем для одного контекста устройства одновременно.
После успешного выбора созданного нами карандаша и запоминания предыдущего выбранного необходимо создать и выбрать кисть. Для этого используем функцию CreateSolidBrush:
hCurBrush:= CreateSolidBrush(RGB(0, 128, 255));
Данная функция имеет следующий формат:
Function CreateSolidBrush(crColor: COLORREF): HBRUSH;
Параметр crColor задает цвет кисти.
Если функция завершилась успешно, то она возвращает дескриптор логической кисти. В противном случае – nil.
После создания кисти выбираем ее с использованием той же самой функции SelectObj ect и запоминаем ранее выбранную.
hOldBrush:= SelectObject(hCurDC, hCurBrush);
Далее рисуем примитивы с использованием полученного контекста устройства с новыми графическими объектами.
Чтобы нарисовать эллипс, используем функцию Ellipse:
Ellipse(hCurDC, 10, 10, 100, 70);
Функция имеет следующий формат:
Function Ellipse(hdc: HDC; nLeftRect, nTopLeft, nRightRect, nBottomRect: Integer): BOOL;
• hdc – дескриптор контекста устройства;
• nLeftRect – задает координату х (в логических единицах) верхнего левого угла описываемого прямоугольника;
• nTopRect – задает координату у (в логических единицах) верхнего левого угла;
• nRightRect – задает координату х (в логических единицах) правого нижнего угла;
• nBottomRect – задает координату у (в логических единицах) правого нижнего угла.
Если функция завершается успешно, то ее результат – ненулевое значение. В противном случае возвращается 0.
Для рисования прямоугольника используется функция Rectangle.
Rectangle(hCurDC, 110, 10, 210, 70);
У данной функции такой же формат, как и у Ellipse, но интерпретация последних четырех параметров немного иная. Они задают сам прямоугольник, а не прямоугольник, описываемый вокруг эллипса.
Далее мы рисуем прямоугольник с округленными углами при помощи функции RoundRect.
RoundRect(hCurDC, 10, 80, 100, 140, 10, 10);
У данной функции первые пять параметров идентичны параметрам предыдущей функции, а последние два задают ширину и высоту эллипса, при помощи которого происходит округление углов прямоугольника.
Следующим примитивом, который мы рисуем, является отрезок. Процесс рисования осуществляется в два этапа. Сначала при помощи функции MoveToEx устанавливается начальная точка отрезка. Затем используем функцию Move То с указанием конечной точки.
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. Результат работы приложения «Рисование примитивов»
Здесь вы можете увидеть, что рисуется в итоге и как параметры функции влияют на это.
6.7. Работа с текстом
Теперь мы разработаем простое приложение, которое будет способно выводить текст под различным углом через определенный интервал времени. Для этого опять сделаем обработку события 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;
Как можно легко заметить, обработчик co6biTHHOnPaint работает по той же схеме, что и в предыдущем примере. Изначально получаем контекст устройства, потом создаем необходимый графический объект и выбираем его вместо установленного по умолчанию. После чего восстанавливаются все атрибуты контекста устройства, а затем он освобождается. Теперь перейдем от общего к частному. Мы создаем логический шрифт на основании указанных характеристик при помощи функции CreateFontlndirect.
hCurFont:= CreateFontlndirect(LogFontData);
Данная функция имеет следующий формат заголовка:
Function CreateFontlndirect(const If: LOGFONT): HFONT;
Параметр If содержит описание характеристик логического шрифта. Если функция завершается успешно, то она возвращает дескриптор логического шрифта. В противном случае ее результатом является nil.
После создания шрифта выбираем его в контексте устройства.
hOldFont:= SelectObject(hCurDC, hCurFont);
Далее устанавливаем режим прозрачности, то есть такой режим, при котором будет выводиться только текст без предварительной заливки фона определенным цветом.
nOldMode:= SetBkMode(hCurDC, TRANSPARENT);
Функция SetBkMode служит для установки режима смешивания фона определенного контекста устройства. Этот режим используется для текста, штриховых кистей, а также для карандашей со стилем, отличным от сплошных линий.
Формат заголовка данной функции следующий:
Function SetBkMode(hdc: HDC; nBkMode: Integer): Integer;
• hdc – задает описатель контекста устройства, для которого устанавливается режим смешивания фона;
• nBkMode – определяет режим смешивания фона, может принимать одно из значений, указанных в табл. 6.3.
Таблица 6.3. Режимы смешивания фона
Если функция завершается успешно, то она возвращает предыдущий установленный режим смешивания фона. В противном случае она возвращает ноль.
Стоит отметить, что данная функция оказывает эффект на стили линий, которые рисуются с использованием карандаша, созданного посредством функции CreatePen. Если карандаш создан при помощи функции ExtCreatePen, то никакого эффекта не будет.
Параметр nBkMode может быть установлен и в другие значения, отличные от указанных, которые специфичны для данного драйвера устройства. GDI передает драйверу устройства полученное специфическое значение.
Теперь необходимо установить определенный цвет текста при помощи функции SetTextColor для нашего контекста устройства.
SetTextColor(hCurDC, RGB(0, 0, 255));
Данная функция имеет следующий формат заголовка:
Function SetTextColor(hdc: HDC; crColor: COLORREF): COLORREF;
Первый параметр задает контекст устройства, для которого устанавливается цвет текста. Второй параметр задает сам цвет, который необходимо установить. В качестве результата функция возвращает предыдущий установленный цвет, но в случае неудачного завершения она возвращает CLRINVALID.
Цвет текста используется при рисовании изображения каждого символа при помощи функций 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
lfOrientation := 0; // наклон символа
// относительно оси oX
lfWeight := FW_BOLD; // вес шрифта
lfItalic := 0;
lfUnderline := 0;
lfStrikeOut := 0;
// кодовая страница по умолчанию
lfCharSet := DEFAULT_CHARSET;
lfOutPrecision := OUT_DEFAULT_PRECIS; // точность
// вывода
lfClipPrecision := CLIP_DEFAULT_PRECIS; // отсечение
// вывода
lfQuality := PROOF_QUALITY; // качество вывода
lfPitchAndFamily := VARIABLE_PITCH or FF_DONTCARE;
// семейство шрифта
lfFaceName := 'Arial'; // название шрифта
end;
TurnTimer.Enabled := True;
end;
Результат работы приложения можно увидеть на рис. 6.2.
Рис. 6.2. Результат работы приложения «Работа с текстом»
Правообладателям!
Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.