Лабораторная работа №06 icon

Лабораторная работа №06



НазваниеЛабораторная работа №06
Дата конвертации30.06.2012
Размер290.2 Kb.
ТипЛабораторная работа
1. /OOP/Лабораторная работа ь00-Введение.doc
2. /OOP/Лабораторная работа ь01-Calc&Type.doc
3. /OOP/Лабораторная работа ь02-Drag&Except.doc
4. /OOP/Лабораторная работа ь03-Font&Phrase.doc
5. /OOP/Лабораторная работа ь04-Menu.doc
6. /OOP/Лабораторная работа ь05-Canvas.doc
7. /OOP/Лабораторная работа ь06-Animation.doc
8. /OOP/Лабораторная работа ь07-Hint&Format.doc
9. /OOP/Лабораторная работа ь08-Notepad&BMP.doc
10. /OOP/Лабораторная работа ь09-StringGrid.doc
11. /OOP/Лабораторная работа ь10-MediaPlayer.doc
12. /OOP/Лабораторная работа ь11-Shape.doc
13. /OOP/Лабораторная работа ь12-Events.doc
14. /OOP/Лабораторная работа ь13-Finally&Except.doc
15. /OOP/Лабораторная работа ь14-Animal.doc
16. /OOP/Лабораторная работа ь15-MyButton.doc
17. /OOP/Темы курсовых работ по курсу ООП.doc
Введение
Лабораторная работа №01
Лабораторная работа №02
Лабораторная работа №03
Лабораторная работа №04
Лабораторная работа №05
Лабораторная работа №06
Лабораторная работа №07
Лабораторная работа 08
Лабораторная работа №09
Лабораторная работа №10
Свойства в Delphi
Лабораторная работа №12 События в Delphi
Chapter 12
Лабораторная работа №14
Лабораторная работа №15
Кнопка (TButton)

Лабораторная работа № 06

Анимация с использованием TCanvas

Использование методов класса TCanvas

Класс TCanvas инкапсулирует много функций рисования интерфейса GDI.
Используя методы класса TCanvas, можно рисовать линии и фигуры, писать текст, копировать целые области из одной канвы в другую и даже растягивать некоторую область канвы, чтобы заполнить ее содержимым большую область.

Рисование линий с помощью методов класса TCanvas

Метод TCanvas .MoveTo () изменяет позицию рисования объекта Canvas. Pen на поверхности канвы. При выполнении следующей строки позиция рисования перемещается в верхний левый угол канвы:

Canvas.MoveTo(0, 0);

Метод TCanvas .LineTo () предназначен для проведения прямой линии из текущей позиции на поверхности канвы в позицию, заданную параметрами функции LineTo (). Совместное использование функций MoveTo () и LineTo () позволяет рисовать прямые линии в любом месте канвы. С помощью следующих строк можно провести прямую линию из верхней левой позиции области клиента формы в нижний правый угол:

Canvas.MoveTo(0, 0);

Canvas.LineTo(ClientWidth, ClientHeight);

Использование методов MoveTo () и LineTo () было показано ранее в разделе, посвященном свойству

TCanvas.Pen.

Рисование фигур с помощью методов класса TCanvas

В классе TCanvas предусмотрены различные методы воспроизведения фигур на канве: Arc (), Chord (), Ellipse (), Pie (), Polygon (), PolyLine (), Rectangle () и RoundRect (). Чтобы нарисовать эллипс, используйте метод Ellipse (), как показано в следующей строке:

Canvas.Ellipse(0, 0, ClientWidth, ClientHeight);

Можно также выполнить запивку любой области канвы с помощью узора кисти, заданного в свойстве Canvas .Brush.Style. При выполнении следующего фрагмента будет нарисован эллипс, закрашенный в соответствии со значением свойства Canvas . Brush. Style:

Canvas.Brush.Style := bsCross;

Canvas.Ellipse(0, 0, ClientWidth, ClientHeight);

Вы уже знаете, как вместо значения свойства Canvas .Brush.Style использовать растровый узор, определяемый свойством TCanvas .Brush.Bitmap. Выше было показано, как с помощью этого узора выполняется заливка некоторой области канвы. Точно так же этот растровый узор применяется и для заливки фигур (мы продемонстрируем это позже).

Некоторые методы рисования фигур на канве принимают дополнительные параметры для описания фигуры, которую нужно нарисовать. Например, метод PolyLine () принимает массив записей TPoint, определяющих позиции (или координаты пикселей) на канве, по которым будет проходить линия в игре "соедини точки". Объект TPoint — это запись в Delphi 4, содержащая координаты (х,у). Он определяется следующим образом:

TPoint = record

X: Integer;

Y: Integer; end;

Пример программы рисования фигур

Листинг 1 иллюстрирует использование различных методов класса TCanvas, предназначенных для рисования фигур на канве.

Листинг 1. Иллюстрация рисования фигур

unit MainFrm; interface

uses

SysUtils, Windows, Messages, Classes, Graphics, Controls, Forms, Dialogs, Menus;

type

TMainForm = class(TForm)

mmMain: TMainMenu;

mmiShapes: TMenuItem;

mmiArc: TMenuItem;

mmiChord: TMenuItem;

mmiEllipse: TMenuItem;

mmiPie: TMenuItem;

mmiPolygon: TMenuItem;

mmiPolyline: TMenuItem;

mmiRectangle: TMenuItem;

mmiRoundRect: TMenuItem;

N1: TMenuItem;

mmiFill: TMenuItem;

mmiUseBitmapPattern: TMenuItem;

procedure mmiFillClick(Sender: TObject);

procedure mmiArcClick(Sender: TObject);

procedure mmiChordClick(Sender: TObject);

procedure mmiEllipseClick(Sender: TObject);

procedure mmiUseBitmapPatternClick(Sender: TObject);

procedure mmiPieClick(Sender: TObject);

procedure mmiPolygonClick(Sender: TObject);

procedure mmiPolylineClick(Sender: TObject);

procedure mmiRectangleClick(Sender: TObject);

procedure mmiRoundRectClick(Sender: TObject);

procedure FormCreate(Sender: TObject);

procedure FormDestroy(Sender: TObject); private

FBitmap: TBitmap; public

procedure ClearCanvas;

procedure SetFillPattern; end;

var

MainForm: TMainForm;

Implementation

{ $R *.DFM)

procedure TMainForm.ClearCanvas; begin

// Очистка содержимого канвы with Canvas do begin

Brush.Style := bsSolid; Brush.Color := clWhite; FillRect(ClientRect); end; end;

procedure TMainForm.SetFillPattern; begin

( Определить, нужно ли рисовать фигуру с использованием растрового узора. Если да, то загрузить файл растра. В противном случае использовать стандартный узор кисти. } if mmiUseBitmapPattern.Checked then

Canvas.Brush.Bitmap := FBitmap else

with Canvas.Brush do begin

Bitmap := nil; Color := clBlue; Style := bsCross; end; end;

procedure TMainForm.mmiFillClick(Sender: TObject); begin

mmiFill.Checked := not mmiFill.Checked; { Если признак mmiUseBitmapPattern был установлен, эту установку нужно отменить и установить свойство использования растра кисти равным nil. } if mmiUseBitmapPattern.Checked then begin

mmiUseBitmapPattern.Checked := not mmiUseBitmapPattern.Checked; Canvas.Brush.Bitmap := nil; end; end;

procedure TMainForm.mmiUseBitmapPatternClick(Sender: TObject); begin

{ Установка признаков mmiFill.Checked и mmiUseBitmapPattern.Checked, которая приведет к вызову процедуры SetFillPattern. Однако если признак mmiUseBitmapPattern станет равным True, свойству Canvas.Brush.Bitmap присваивается значение nil. } mmiUseBitmapPattern.Checked := not mmiUseBitmapPattern.Checked; mmiFill.Checked := mmiUseBitmapPattern.Checked; if not mmiUseBitmapPattern.Checked then

Canvas.Brush.Bitmap := nil; end;

procedure TMainForm.mmiArcClick(Sender: TObject); begin

ClearCanvas;

with ClientRect do

Canvas.Arc(Left, Top, Right, Bottom, Right, Top, Left, Top); end;

procedure TMainForm.mmiChordClick(Sender: TObject); begin

ClearCanvas;

with ClientRect do

begin

if mmiFill.Checked then

SetFillPattern;

Canvas.Chord(Left, Top, Right, Bottom, Right, Top, Left, Top); end;

end;

procedure TMainForm.mmiEllipseClick(Sender: TObject); begin

ClearCanvas;

if mmiFill.Checked then SetFillPattern;

Canvas.Ellipse(0, 0, ClientWidth, ClientHeight); end;

procedure TMainForm.mmiPieClick(Sender: TObject); begin

ClearCanvas;

if nuniFill.Checked then SetFillPattern;

Canvas.Pie(0, 0, ClientWidth, ClientHeight, 50, 5, 300, 50); end;

procedure TMainForm.mmiPolygonClick(Sender: TObject); begin

ClearCanvas;

if mmiFill.Checked then

SetFillPattern; Canvas.Polygon([Point(0, 0), Point (150, 20), Point(230, 130),

Point (40, 120)]); end;

procedure TMainForm.mmiPolylineClick (Sender: TObject); begin

ClearCanvas;

Canvas.PolyLine([Point(0, 0), Point (120, 30), Point(250, 120),

Point(140, 200), Point(80, 100), Point(30, 30)]); end;

procedure TMainForm.mraiRectangleClick(Sender: TObject); begin

ClearCanvas;

if mmiFill.Checked then SetFillPattern;

Canvas.Rectangle(10 , 10, 125, 240); end;

procedure TMainForm.mmiRoundRectClick(Sender: TObject); begin

ClearCanvas;

if mmiFill.Checked then SetFillPattern;

Canvas.RoundRect(15, 15, 150, 200, 50, 50); end;

procedure TMainForm.FormCreate(Sender: TObject); begin

FBitmap := TBitmap.Create;

FBitMap.LoadFromFile('Pattern.bmp1);

Canvas.Brush.Bitmap := nil; end;

procedure TMainForm.FormDestroy(Sender: TObject); begin

FBitmap.Free; end;

end.

Функции рисования фигур выполняются обработчиками событий главного меню. Два открытых (public) метода, ClearCanvas () и SetFillPattern (), служат для этих обработчиков событий вспомогательными функциями. При выборе одного из первых восьми элементов меню вызывается соответствующая функция рисования фигуры на канве формы, а с помощью двух последних элементов меню, Fill (Залить) и Use Bitmap Pattern (Использовать растровый узор), определяется, каким образом нужно выполнить заливку формы: одним из стандартных узоров кисти или с применением файла растрового узора соответственно.

Метод SetFillPatern ( ) предназначен для определения способа заливки фигур, нарисованных другими методами: с помощью одного из стандартных узоров кисти либо растрового файла узора. Если выбран растровый файл, он назначается свойству Canvas.Brush.Bitmap.

Все обработчики событий, приступающие к рисованию фигуры, прежде всего обращаются к функции С1еагСanvas () для стирания всего, что было нарисовано ранее. Затем, если свойство mmiFill.Checked установлено равным Тrue, они вызывают функцию SetFillPatern ( ). И только после всего этого выполняется рисование соответствующей фигуры путем вызова нужного метода класса ТСаnvas. Комментарии, приведенные в исходном тексте программы, разъясняют назначение каждой функции. Тем не менее, метод mmiPolylineClick ( ) заслуживает отдельного обсуждения.

В процессе рисования фигур их внутреннюю область, ограниченную замкнутым контуром, необходимо залить либо стандартным узором кисти, либо узором из растрового файла. И хотя, казалось бы, ничто не мешает использовать методы Polyline() и FoodFill() для создания замкнутой границы, заполненной каким-нибудь узором, прибегать к этому способу все-таки не рекомендуется. Метод Polyline() применятся исключительно для рисования линий. Если же вам нужно нарисовать закрашенные многоугольники, вызовите метод TCanvas.Polygon ( ) . Функция Polyline ( ) при рисовании линий образует неточность в 1 пиксель, которая при обращении к функции FoodFill ( ) выливается в заливку всей канвы. При применении функции Polyline() для рисования фигур с заливкой используются математические методы, которые защищены от подобных колебаний в позиционировании пикселей.

Выведение текста с помощью методов класса ТСаnvas

Класс ТСаnvas инкапсулирует функции интерфейса Win32 GDI для вывода текста на поверхность рисования. Их использованию и будет уделено внимание в следующих разделах. Кроме того, вы узнаете, как использовать другие функции, которые не инкапсулированы классом ТCanvas.

Использование функций вывода текста, принадлежащих классу ТСаnvas

Как отмечалось в предыдущих главах, для вывода текста на поверхность рисования используется определенная в классе ТСаnvas функция ТехtOut () . Однако класс ТСаnvas содержит и некоторые другие полезные методы (ТехtWidth () и ТехtHeight ()), предназначенные для определения размера текста в строке (в пикселях), использующей шрифт, воспроизводимый классом ТСаnvas. В следующем фрагменте программы определяется ширина и высота строки "Dе1рhi 6 — Уеs!":

Vаr

S : string

W, h : integer;

begin

S := 'Delphi 6 - Yes ! ' ;

w := Саnvas.ТехtWidth (s) ;

Ь := Canvas. Textheight (s) ;

end.

Существует также метод ТехtRect ( ) , который записывает текст на форму, но при этом помещает его только внутрь прямоугольника, заданного структурой ТRect. Текст, не поместившийся в пределах границ ТRect, усекается. В следующем примере

Саnvas.ТехtRect (R, 0, 0, 'Dе1рhi 6 Уеs ! ' ) ;

строка "Delphi 6 – Yes” записывается на канву, начиная с позиции 0,0. Однако та часть строки, которая выпадает за пределы координат, заданных параметром R (имеющим тип структуры ТRect), отсекается.

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

Листинг 2. Операции вывода текста

Unit MainFrm;

Interface;

Uses SysUtils, Windows, Messages, Classes, Graphics

Controls, Forms, Dialogs, Menus;

const

DString = 'Delphi 4 YES!'; DString2 = 'Delphi 4 Rocks!';

type

TMainForm = class(TForm)

mmMain: TMainMenu;

mmiText: TMenuItem;

rtmiTextRect: TMenuItem;

mmiTextSize: TMenuItem;

mmiDrawTextCenter: TMenuItem;

mmiDrawTextRight: TMenuItem;

mmiDrawTextLeft: TMenuItem;

procedure mmiTextRectClick(Sender: TObject);

procedure mmiTextSizeClick(Sender: TObject);

procedure mmiDrawTextCenterClick(Sender: TObject);

procedure mmiDrawTextRightClick(Sender: TObject);

procedure rraniDrawTextLeftClick(Sender: TObject); public

procedure ClearCanvas; end; var

MainForm: TMainForm;

implementation { $R *.DFM}

procedure TMainForm.ClearCanvas; begin

with Canvas do begin

Brush.Style := bsSolid; Brush.Color := clWhite; FillRect(ClipRect);

end;

end;

procedure TMainForm.mmiTextRectClick(Sender: TObject); var

R: TRect;

TWidth, THeight: integer; begin

ClearCanvas;

Canvas.Font.Size := 18;

// Вычисление ширины/высоты строки текста

TWidth := Canvas.TextWidth(DString);

THeight := Canvas.TextHeight(DString);

{ Инициализация структуры TRect. Высота этого прямоугольника

будет равна половине высоты строки текста, чтобы проиллюстрировать усечение текста границами прямоугольника. }

R := Rectd, THeight div 2, TWidth + I, THeight+(THeight div 2));

// Рисование прямоугольника на основе размеров текста

Canvas.Rectangle(R.Left-1, R.Top-1, R.Right+1, R.Bottom+1);

// Вывод текста внутри прямоугольника

Canvas.TextRect(R,0,0,DString);

end;

procedure TMainForm.mmiTextSizeClick(Sender: TObject); begin

ClearCanvas; with Canvas do begin

Font.Size := 18;

TextOut(10, 10, DString);

TextOut(50, 50, ' TextWidth = '+IntToStr(TextWidth(DString)));

TextOutdOO, 100, 'TextHeight = '+IntToStr(TextHeight(DString)));

end;

end;

procedure TMainForm.mmiDrawTextCenterClick(Sender: TObject); var

R: TRect; begin

ClearCanvas;

Canvas.Font.Size := 10;

R := Rect (10, 10, 80, 100) ;

// Рисование прямоугольника, обводящего объект TRect

// границей, отстоящей на 2 пикселя

Canvas.Rectangle(R.Left-2, R.Top-2, R.Right+2, R.Bottom+2);

// Вывод текста по центру путем задания опции dt_Center

DrawText(Canvas.Handle, PChar(DString2), -1, R, dt_WordBreak or

2dt_Center); end;

procedure TMainForm.mmiDrawTextRightClick(Sender: TObject); var

R: TRect; begin

ClearCanvas;

Canvas.Font.Size := 10;

R := Rect(10, 10, 80, 100) ;

// Рисование прямоугольника, обводящего объект TRect

// границей, отстоящей на 2 пикселя

Canvas.Rectangle(R.Left-2, R.Top-2, R.Right+2, R.Bottom+2);

// Вывод текста с выравниванием вправо путем задания опции dt_Right

DrawText(Canvas.Handle, PChar(DString2), -1, R, dt_WordBreak or dt_Right); end;

procedure TMainForm.mmiDrawTextLeftClick (Sender: TObject); var

R: TRect; begin

ClearCanvas;

Canvas.Font.Size := 10;

R := RectdO, 10, 80, 100) ;

// Рисование прямоугольника, обводящего объект TRect

// границей, отстоящей на 2 пикселя

Canvas.Rectangle(R.Left-2, R.Top-2, R.Right+2, R.Bottom+2);

// Вывод текста с выравниванием влево путем задания опции dt_Left

DrawText(Canvas.Handle, PChar(DString2), -1, R, dt_WordBreak or dt_Left); end;

end.

Как и все предыдущие проекты, данный проект содержит метод ClearCanvas (), используемый для стирания содержимого канвы формы.

Различные методы главной формы являются обработчиками событий для главного меню формы.

Использование метода TCanvas .TextRect () иллюстрируется с помощью метода mmiTextRectClick (), в котором сначала определяется ширина и высота заданного текста, а затем этот текст выводится внутри прямоугольника с высотой, равной половине высоты заданного размера шрифта. Результат работы этого метода показан на рис. 1





Рис. 1. Результат работы метода mmiTextRectClick()

На примере функции mmiTextSizeClick() показано, как определяется размер текстовой строки с помощью методов ТСanvas.TextWidth() и ТCanvas.textHeight (). Результат работы этой функции показан на рис. 2.



Рис. 2. Результат работы функции mmiTextSizeClick ()

Использование GDI-функций вывода текста, не принадлежащих классу ТСanvas

В приведенном выше примере с помощью методов mmiDrawTextCenter (), mmiDrawTextLeft () и mmiDrawTextRight () демонстрируется использование функции Win32 GDI DrawTExt (), которая не инкапсулируется классом ТСаnvas.

Посмотрев на описание таких функций GDI, как BitBlt () или DrawTetx (), вы обнаружите, что одним из обязательных параметров является контекст устройства (DС). Доступ к контексту устройства осуществляется через свойство канвы Наndle, т.е. свойство ТСаnvas. Наndle является контекстом устройства (DС) для данной канвы.

Контексты устройств (Device Context) представляют собой дескрипторы, предусмотренные интерфейсом Win32 для идентификации связи приложения Win32 через драйвер устройства с такими выходными устройствами, как монитор, принтер или плоттер. В традиционном Windows-ориентированном программировании для прорисовки поверхности окна программист должен был сам позаботиться о запросе на получение ОС. По завершении операции он обязан был вернуть ОС системе.

В Delphi упрощен процесс работы с ОС путем инкапсуляции управления ОС в классе TCanvas, который даже кэширует ваш DС, сохраняя его "про запас", чтобы уменьшить частоту запросов к Win32 и тем самым увеличить общее быстродействие вашей программы.

Чтобы показать, как используется класс ТСаnvas с функцией Win32 GDI, в приведенном выше листинге была применена функция GDI DrawТехt () для вывода текста с дополнительными возможностями форматирования. Эта функция принимает пять описанных ниже параметров.



Параметр

Описание

DC

Контекст устройства поверхности рисования

Str

Указатель на буфер, который содержит подлежащий выводу текст. Если параметр Соunt равен -1 , то это должна быть строка с ограничивающим нуль -символом

Count

Число байтов в строке Str. Если это значение равно -1 , то Str должен указывать на строку с ограничивающим нуль - символом

Rect

Указатель на структуру TRect, содержащую координаты прямоугольника, в котором форматируется текст

Format

Битовое поле с признаками, определяющими различные опции форматирования для параметра Str

В приведенной выше программе структура ТRect инициализируется с помощью функции Rect (). Эта структура используется для рисования прямоугольника вокруг текста, выводимого с использованием функции DrawText (). Каждый из трех методов передает этой функции различный набор признаков форматирования. Признаки dt_WordBreak и dt_Center используются для центрирования текста в прямоугольнике, заданном переменной к типа ТRect. Объединенные операцией логического ИЛИ признаки форматирования dt_WordBreak и dt_Right служат для выравнивания текста в прямоугольнике по правому краю, а dt_WordBreak и dt_Left.— для выравнивания по левому краю. Спецификатор dt_WordBreak предназначен для переноса слов на новую строку в пределах границы, обусловленной шириной (которая задается соответствующим параметром прямоугольника), и для модификации высоты прямоугольника после реализации этого переноса слов.

Результат работы метода mmiDrawTextCenterClick () показан на рис. 3.

Класс ТСаnvas также содержит методы Draw (), Сору (), CopyRect () и StretchDraw (), с помощью которых можно рисовать, растягивать и сжимать изображения или их части либо копировать на другую канву.


Координатные системы и режимы отображения

Большинство GDI функций рисования требуют набор координат, который задает позицию для рисования. Эти координаты зависят от такой единицы измерения, как пиксель. Кроме того, GDI функции работают с учетом определенной ориентации осей координат. Интерфейс Win32 при выполнении функций рисования опирается на координатную систему и режим отображения области рисования.




Рис. 3. Результат работы метода ттiDrawTextCenterClick()

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

Координаты устройства

Как следует из названия, эти координаты связаны с устройством, на котором работает интерфейс Win32. Их единицами измерения являются пиксели, а ориентация горизонтальной и вертикальной осей такова, что значения координат увеличиваются слева направо и сверху вниз. Например, если запустить Windows на дисплее с разрешением 640x480, то координаты точки в верхнем левом углу вашего устройства будут равны (0,0), а в нижнем правом углу — (639,479).

Логические координаты

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

Координаты экрана

Координаты экрана имеют прямое отношение к дисплею и поэтому измеряются в пикселях. Для дисплея с разрешением 640x480 свойства Screen.Width и Screen.Height равны 640 и 480 пикселей соответственно. Чтобы получить контекст устройства экрана, используйте функцию Win32 АР1 GetDC(). При этом любая функция, считывающая контекст устройства, должна работать совместно с функцией ReleaseDC (); эта согласованность иллюстрируется следующим фрагментом:

Var

ScreenDC: НDС; begin

ScreenDС := GetDC(0);

try

{ Любые действия, использующие контекст устройства ScreenDC }

finally

ReleaseDC (0, ScreenDC);

End;

End;


Координаты формы

Координаты формы можно считать синонимом термина координаты окна, когда рассматривается форма целиком или окно, включающее строку заголовка и ограничивающую рамку. В Delphi не предусмотрено такого свойства формы, которое бы содержало значение DC для области рисования формы, но его можно получить с помощью функции Win32 API GetWindowDC ():

MyDC := GetWindowDC(Form1.Handle);

Эта функция возвращает контекст устройства для дескриптора окна, переданного ей в качестве параметра.

Для инкапсуляции значений контекстов устройств, получаемых при обращениях к функциям GetDC() и GetWindowDC(), можно использовать объект TCanvas, что позволит применять методы класса TCanvas вместо явных значений контекстов устройств. Для этого достаточно создать экземпляр класса TCanvas, а затем присвоить результат вызова функции GetDC() или GetWindowDC() свойству TCanvas. Handle. Работоспособность этого подхода достигается благодаря тому, что класс приобретает право собственности на присвоенный ему дескриптор, после чего несет за него полную ответственность, освобождая DC при освобождении канвы. Вот фрагмент, иллюстрирующий описанный метод:

var

с: TCanvas; begin

с :=TCanvas.Create; try

с.Handle :=GetDC{0);
c.TextOut(0, 10, 'Hello World') ;
finally

c.Free;
end;

end;

Координаты области клиента формы относятся к области клиента формы, контекст устройства (DC) которой равен значению свойства Handle канвы (объекта Canvas) формы, а размеры можно получить с помощью свойств Canvas . ClientWidth и Canvas . ClientHeight.

Отображение координат

Так почему же при работе с функциями рисования не использовать просто координаты устройства вместо логических координат? Рассмотрим следующую строку кода:

Forml.Canvas.TextOut(0, 0, 'Upper Left Corner of Form');

При выполнении этой программной строки заданная строка текста размещается в верхнем левом углу формы. Заданные координаты (0,0) указывают на позицию (0,0) в контексте устройства формы, т.е. являются логическими. Но позиция (0,0) для данной формы имеет совершенно другие значения в системе координат устройства и зависит от конкретного расположения формы на экране. Если верхний левый угол формы совпадает с верхним левым углом экрана, то координаты формы (0,0) могут и в самом деле совпасть с позицией (0,0) в координатах устройства. Однако при перемещении формы на другое место точка с координатами формы (0,0) будет соответствовать совершенно другой позиции, определяемой в координатах устройства.

Для преобразования логических координат точки в координаты устройства и наоборот

используйте функции Win32 API ClientToScreen() и ScreenToClient () соответственно. Эти функции являются также методами класса TControl. Обратите внимание на то, что они работают только с контекстами устройств экрана, связанными с видимыми элементами управления. Для контекста устройства принтера или метафайла, которые не имеют отношения к экрану, преобразование логических пикселей в пиксели устройства и обратно выполняется с помощью функций Win32 LPtoDP () и DPtoLP () соответственно.

При выполнении метода Canvas.TextOut () в действительности используются координаты устройства. Для этого интерфейс Win32 должен преобразовать логические координаты конкретного DС в координаты устройства. Это достигается за счет использования определенного режима отображения, связанного с DС.

Другая причина использования логических координат— нежелание использовать пиксели для работы с функциями рисования. Вполне вероятно, что при рисовании вам удобнее работать с такими единицами измерения, как дюймы или миллиметры. Win32 позволяет изменять единицы измерения путем изменения режима отображения, как будет показано ниже.

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

Возможно, режимы отображения, режимы рисования, ориентация и тому подобные вещи не кажутся связанными столь уж очевидным образом с контекстом устройства, поскольку в Delphi для
рисования используется канва. Напомним, что класс TCanvas является оболочкой для DС. Эта связь
становится более явной при сравнении функций Win32 GDI с эквивалентными методами объектами Canvas:

метод класса ТCanvas: Саnvas.Rectangle(0,0,50,50);

функция GDI: Rectangle(ADC,0,0,50,50);

При использовании функции GDI требуется явная передана контекста устрой в то время как метод канвы использует DС неявным образом за счет инкапсуляции.

В Win32 предусмотрена возможность задания режима отображения для ТСаnvas .Наndle. Определено восемь режимов отображения, которыми можно воспользоваться в соответствии с потребностями


Режим отображения

Размер логической единицы измерения

Ориентация (Х,У)

ММ_ANISOTROPIC

Произвольно (х <> у или х = у)

Задаваемая/Задаваемая

ММ_НIENGLISH

0.001 дюйма

Направо/Вверх

ММ_НIMETRIC

0.01 мм

Направо/Вверх

ММ_ISOTROPIC

Произвольно (х = у)

Задаваемая/Задаваемая

ММ_LOENGLISH

0.01 дюйма

Направо/Вверх

ММ_ LOMETRIC


0.1 мм

Направо/Вверх

ММ_ТЕХТ

1 пиксель

Направо/Вниз

ММ_ТWIPS

1/1440 дюйма

Направо/Вверх

Программирование анимации

Здесь показано, как, объединив классы Delphi с функциями Win32 GDI, можно добиться анимации упрощенного изображения эльфа. В листинге 3 содержатся методы, обеспечивающие функционирование главной формы.

Листинг 3. Главная форма проекта создания анимации

unit MainFrm; interface

uses

SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, Menus, Stdctrls;

{ $R SPRITES.RES } // Привязка растровых изображений к исполняемому файлу

type

TSprite = class private

FWidth: integer;

FHeight: integer;

FLeft: integer;

FTop: integer;

FAndlmage, FOrlmage: TBitMap; public

property Top: Integer read FTop write FTop;

property Left: Integer read FLeft write FLeft;

property Width: Integer read FWidth write FWidth;

property Height: Integer read FHeight write FHeight;

constructor Create;

destructor Destroy; override; end;

TMainForm = class(TForra)

procedure FormCreate(Sender: TObject);

procedure FormPaint(Sender: TObject);

procedure FormDestroy(Sender: TObject); private

BackGndl, BackGnd2: TBitMap;

Sprite: TSprite;

GoLeft,GoRight,GoUp,GoDown: boolean;

procedure MyldleEvent(Sender: TObject; var Done: Boolean);

procedure DrawSprite;

end;

const

BackGround = 'BACK2.BMP';

var

MainForm: TMainForm;

implementation { $R *.DFM}

constructor TSprite.Create;

begin

inherited Create;

( Создание растров для хранения изображений эльфа, которые будут использованы при выполнении операции AND/OR (И/ИЛИ) для создания анимации. }

FAndlmage := TBitMap.Create; FAndlmage.LoadFromResourceName(hlnstance, 'AND');

FOrImage := TBitMap.Create;

FOrImage.LoadFromResourceName(hlnstance, 'OR');

Left := 0;

Top := 0;

Height := FAndlmage.Height;

Width := FAndlmage.Width;

end;

destructor TSprite.Destroy;

begin

FAndlmage.Free;

FOrImage.Free;

end;

procedure TMainForm.FormCreate(Sender: TObject);

begin

// Создание исходного фонового изображения BackGndl := TBitMap.Create; with BackGndl do begin

LoadFromResourceName(hlnstance, 'BACK') ;

Parent :=> nil;

SetBounds(0, 0, Width, Height); end;

// Создание копии фонового изображения BackGnd2.Assign(BackGndl);

// Создание изображения эльфа

Sprite := TSprite.Create;

// Инициализация переменных направления

GoRight := True; GoDown := True; GoLeft := False; GoUp := False;

( Установка события приложения Onldle равным значению MyldleEvent, с которого начнется движение эльфа. }

Application.Onldle := MyldleEvent; // Установка высоты и ширины области клиента формы ClientWidth := BackGndl.Width; ClientHeight := BackGndl .Height

end;

procedure TMainForm.FormDestroy(Sender: TObject);

begin

// Освобождение всех объектов, созданных в конструкторе формы FormCreateO

BackGndl.Free;

BackGnd2. Free,• Sprite.Free;

end;

procedure TMainForm.MyldleEvent(Sender: TObject; var Done: Boolean);

begin

DrawSprite;

{ Разрешение вызова события Onldle даже при отсутствии сообщений в очереди сообщений приложения. )

Done := False;

end;

procedure TMainForm.DrawSprite;

var

OldBounds: TRect;

begin

// Сохранение границ эльфа в объекте OldBounds

with OldBounds do

begin

Left := Sprite.Left;

Top := Sprite.Top;

Right := Sprite.Width;

Bottom := Sprite. Height-end;

{ Теперь изменяем границы эльфа, чтобы он двигался в одном направлении,

или изменяем направление при соприкосновении с границами формы. } with Sprite do begin

if GoLeft then if Left > 0 then

Left := Left - 1 else begin

GoLeft := False; GoRight := True; end;

if GoDown then

if (Top + Height) < self.ClientHeight then

Top := Top + 1 else begin

GoDown := False; GoUp := True; end;

if GoUp then

if Top > 0 then

Top := Top - 1 else begin

GoUp := False; GoDown := True; end;

if GoRight then

if (Left + Width) < self.ClientWidth then

Left := Left + 1 else begin

GoRight := False;

GoLeft := True;

end;

end;

{ Стираем исходное изображение эльфа на фоне BackGnd2 путем

копирования прямоугольника из фона BackGndl. } with OldBounds do

BitBlt(BackGnd2.Canvas.Handle, Left, Top, Right, Bottom, BackGndl.Canvas.Handle, Left, Top, SrcCopy);

{ Теперь рисуем эльфа на "внеэкранном" растре, тем самым

избавляясь от мерцания. } with Sprite do begin

{ Создадим черное пятно с силуэтом эльфа с помощью операции

логического И, выполненной над растрами FAndlmage и BackGnd2. } BitBlt(BackGnd2.Canvas.Handle, Left, Top, Width, Height,

FAndlmage.Canvas.Handle, 0, 0, SrcAnd);

// Выполним заливку черного пятна исходными цветами эльфа BitBlt(BackGnd2.Canvas.Handle, Left, Top, Width, Height,

FOrImage.Canvas.Handle, 0, 0, SrcPaint);

end;

( Копируем эль4>а в его новой позиции на канву формы. При этом используется прямоугольник, который немного больше, чем нужно для фигуры эльфа. Тем самым мы добиваемся эффективного стирания эльфа путем его перезаписи, после чего рисуем нового эльфа в новой позиции с помощью одного вызова функции BitBlt. }

with OldBounds do

BitBlt(Canvas.Handle, Left - 2, Top - 2, Right + 2, Bottom + 2,

BackGnd2.Canvas.Handle, Left - 2, Top - 2, SrcCopy);

end;

procedure TMainForm.FormPaint(Sender: TObject);

begin

// Рисуем фоновое изображение при закрашивании формы BitBlt(Canvas.Handle, О, О, ClientWidth, ClientHeight,

BackGndl.Canvas.Handle, 0, 0, SrcCopy);

end;

end.

Как работает проект создания анимации

Анимационный проект состоит из фонового изображения и нарисованного на нем эльфа в виде летающего блюдца, которое перемещается в пределах области клиента фона. Фон представлен растровым изображением разбросанных по небу звезд (рис. 4).




Эльф составлен из двух растров размером 64x32. О них речь пойдет ниже, а пока рассмотрим, что происходит в программе.

В приведенном модуле определяется класс TSprite, который содержит поля, предназначенные для хранения позиций эльфа на изображении фона, и два объекта типа TBitmap для хранения растровых изображений эльфа. Конструктор TSprite.Create создает оба экземпляра класса TBitmap и загружает их реальными растрами. Оба растровых изображения эльфа и фоновый растр содержатся в файле ресурсов, который привязывается к проекту путем включения в основной модуль следующей инструкции:

( $R SPRITES.RES }

После загрузки растра устанавливаются границы изображения эльфа. Деструктор TSprite. Done освобождает оба экземпляра растра.

Главная форма содержит два объекта типа TBitmap, объект TSprite и индикаторы направлений, задающие линию движения эльфа. Кроме того, в главной форме определены два метода: MyldleEvent (), служащий обработчиком событий Application.Onldle, и DrawSprite (), предназначенный для рисования изображения эльфа.

Обработчик событий FormCreate () создает оба экземпляра класса TBitmap и загружает каждый одним и тем же растровым изображением (зачем — разберемся чуть ниже). Затем создается экземпляр класса TSprite, устанавливаются значения индикаторов направлений и обработчику событий Application.Onldle назначается метод MyldleEvent (). Наконец, обработчик событий формы FormCreate () изменяет размеры формы в соответствии с размерами фонового изображения.

Метод FormPaint () выполняет рисование на канве фона BackGndl.

Метод FormDestroy () освобождает экземпляры классов TBitmap и TSprite.

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

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


Для достижения поставленных целей процесс рисования выполняется на "внеэкранном" растре BackGnd2. Растры BackGnd2 и BackGndl являются точными копиями фонового изображения, однако BackGndl никогда не модифицируется (поэтому его можно назвать чистой копией фона). По завершении рисования модифицированная область растра BackGnd2 копируется на канву формы. Это позволяет за одно обращение к функции BitBlt () выполнить как стирание на канве формы, так и рисование эльфа в новой позиции. Какие же операции выполняются с растром BackGnd2?

Во-первых, из BackGndl в BackGnd2 копируется прямоугольный участок, превышающий по размерам область, занимаемую самим эльфом. Тем самым гарантируется стирание изображения эльфа с растра BackGnd2. После этого растр FAndlmage копируется в BackGnd2 на его новой позиции с помощью поразрядной операции AND (логическое И). Это приводит к созданию черного пятна с силуэтом эльфа, но с сохранением цветов в области растра BackGnd2, окружающей черный силуэт. Растр FAndlmage показан на рис. 5.




Рис. 5. Растр FAndImage для эльфа

На рис. 5 эльф представлен черными пикселями, а изображение вокруг эльфа состоит из белых пикселей. Черный цвет имеет значение, равное 0, а белый— 1. В таблицах приведены результаты выполнения операции AND с белым и черным цветами.

Таблица Операция AND с черным цветом


Фон

Значение

Цвет

BackGnd2

1001

Некоторый цвет

FAndlmage

0000

Черный

Результат

0000

Черный

Таблица Операция AND с белым цветом

Фон

Значение

Цвет

BackGnd2

1001

Некоторый цвет

FAndlmage

1111

Белый

Результат

1001

Некоторый цвет

Обе таблицы показывают, как выполнение операции логического и приводит к зачернению области, занимаемой эльфом на растре BackGnd2. В таблице столбец "Значение" представляет цвет пикселя. Если пиксель на растре BackGnd2 содержит некоторый произвольный цвет, то объединение этого цвета с черным при использовании оператора AND заставит этот пиксель полностью почернеть. Аналогичная операция, выполненная над тем же цветом и абсолютно белым "коллегой" никак не отразится на исходном цвете, как видно в таблице. А поскольку цвет фона, на котором находился эльф в растре FAndlmage, был белым, то пиксели на растре BackGnd2 копируются без изменения своих цветов.

После копирования растра FAndlmage в объект BackGnd2 растр FOrImage должен быть скопирован в то же самое место растра BackGnd2, чтобы заполнить черное пятно, созданное объединением растра FAndlmage с реальными цветами эльфа. Растр FOrlmage также имеет прямоугольник, окружающий реальное изображение эльфа. И вновь мы сталкиваемся с задачей получения цветов эльфа для растра BackGnd2 и одновременным сохранением цветов этого растра в области, окружающей эльфа. Это достигается объединением растров FOrlmage и BackGnd2 с использованием оператора OR (логическое ИЛИ). Растр FOrlmage показан на рис. 6.




Обратите внимание на то, что область, окружающая изображение эльфа, окрашена в черный цвет. В таблице показаны результаты выполнения операции ИЛИ с растрами FOrlmage и BackGnd2.

Из таблицы следует, что если растр BackGnd2 содержит произвольный цвет, то после операции логического сложения с черным цветом останется тот же цвет растра BackGnd2.

Напомним, что все рисование выполняется на "внеэкранном" растре. По завершении рисования достаточно только одного обращения к функции ВitBlt ( ) , чтобы стереть и скопировать изображение эльфа.

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


Таблица. Операция OR с черным цветом

Фон

Значение

Цвет

BackGnd2

1001

Некоторый цвет

FOrImage

0000

Черный цвет

Результат

1001

Некоторый цвет

Задание:

1. Модернизировать работу программы, чтобы «эльф» управлялся клавишами с клавиатуры.

2. Модернизировать программу в сторону игровой, т.е. предусмотреть «стрельбу».




Похожие:

Лабораторная работа №06 iconЛабораторная работа: создание мини-презентации «Памятники Кремля»
Лабораторная работа проводится в компьютерном классе, с подключением к сети Internet
Лабораторная работа №06 iconДокументы
1. /Lab1/Лабораторная работа 1.doc
2. /Lab2/Лабораторная...

Лабораторная работа №06 iconИ я забуду Покажи мне и я запомню, Дай мне действовать самому и я научусь. Китайская мудрость Тема: Лабораторная работа
Тема: «Лабораторная работа «Измерение работы и мощности тока в электрической лампочке»
Лабораторная работа №06 iconДокументы
1. /Nash/lab1/Лабораторная работа ь1.doc
2. /Nash/lab10/Лабораторная...

Лабораторная работа №06 iconЛабораторная работа №2 «Система безопасности Windows xp»
Лабораторная работа №2 «Система безопасности Windows xp» Цель работы: Изучить систему безопасности Windows xp
Лабораторная работа №06 iconЛабораторная работа «Работа в Windows c помощью основного меню. Использование технологии ole»
Запишите размер папки, выраженный в Мб (мегабайтах) в текстовый редактор блокнот
Лабораторная работа №06 iconЛабораторная работа «Работа с текстовыми фрагментами без помощи мыши»
Скопируйте последнее слово получившегося текста и вставьте его в начало текста один раз
Лабораторная работа №06 iconДокументы
1. /Базовые задачи на обработку массива.doc
2. /ЗадачиНаЛиниВетвление.doc
Лабораторная работа №06 iconДокументы
1. /laba/Лабораторная работа ь1.doc
2. /laba/Лабораторная...

Лабораторная работа №06 iconДокументы
1. /механизация/~$б работа ь4.doc
2. /механизация/~$бораторная...

Разместите кнопку на своём сайте:
Документы


База данных защищена авторским правом ©podelise.ru 2000-2014
При копировании материала обязательно указание активной ссылки открытой для индексации.
обратиться к администрации
Документы

Разработка сайта — Веб студия Адаманов