Автор Тема: Delphi (TImage)  (Прочитано 28138 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Acider

  • Пользователь
  • Сообщений: 237
    • Просмотр профиля
Delphi (TImage)
« : 18 Октябрь 2007, 14:43:12 »
Привет программерам. У меня такой вопрос. Подскажите плиз, где у компонента TImage можно менять, что бы он был на заднем или на переднем плане. А, то когда делал игру одного перса в первый имидж кинул другого во второй, а на последок над фоном стал работать. Не, впринцыпе можно попарить себе мозги и поменять картинки в имиджах и потом во всех кодах с загрузками картинок, поменять номер имиджа. Но мож все таки как то можно проще, просто поставить Image3 на задний план? Подскажите плиз. Заранее благодарен.

Оффлайн HoRRoR

  • Пользователь
  • Сообщений: 983
  • Пол: Мужской
  • Ромхакер
    • Просмотр профиля
Delphi (TImage)
« Ответ #1 : 18 Октябрь 2007, 18:00:11 »
А чем тебя правый клик по Image3, Control->Send to back не устраивает?

Оффлайн Zephyr

  • Пользователь
  • Сообщений: 544
  • Пол: Мужской
  • coder
    • Просмотр профиля
Delphi (TImage)
« Ответ #2 : 18 Октябрь 2007, 18:55:00 »
4.2 Отображение графики на канве Canvas
Канва Canvas не является компонентом, так что, строго говоря, она не должна бы рассматриваться в рамках данной книги. Но поскольку многие компоненты, в частности, формы, имеют канву и канва предоставляет возможность выводить различную графическую информацию, то некоторые начальные сведения о канве все-таки целесообразно дать.

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

Каждая точка канвы имеет координаты X и Y. Система координат канвы, как и везде в Delphi, имеет началом левый верхний угол канвы. Координата X возрастает при перемещении слева направо, а координата Y — при перемещении сверху вниз. Координаты измеряются в пикселях. Пиксель — это наименьший элемент поверхности рисунка, с которым можно манипулировать. Важнейшее свойство пикселя — его цвет.

Канва имеет свойство Pixels. Это свойство представляет собой двумерный массив, который отвечает за цвета канвы. Например, Canvas.Pixels[10,20] соответствует цвету пикселя, 10-го слева и 20-го сверху. С массивом пикселей можно обращаться как с любым свойством: изменять цвет, задавая пикселю новое значение, или определять его цвет по хранящемуся в нем значению. Например, Canvas.Pixels[10,20] := 0 или Canvas.Pixels[10,20] := clBlack — это задание пикселю черного цвета.

Свойство Pixels можно использовать для рисования на канве. Давайте попробуем нарисовать по пикселям график синусоиды на канве формы. Для этого в обработчик события формы OnPaint (прорисовка) можно вставить следующий код:

procedure TForm1.FormPaint(Sender: TObject);
 var
  X,Y: real;      //  координаты функции
  PX,PY: longint; //  координаты пикселей
begin
 Color := clWhite;
 for PX := 0 to ClientWidth do
  begin
   {X — аргумент графика,
    соответствующий пикселю с координатой РХ}
   X := PX*4*Pi/ClientWidth;
   Y:=Sin(X);
   {PY — координата пикселя,
    соответствующая координате Y}
   PY:=trunc(ClientHeight - (Y+1)*ClientHeight/2);
   {Устанавливается черный цвет выбранного
    пикселя (О яркости)}
   Canvas.Pixels [PX, PY] := 0;
  end;
end;

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

Рис. 4.1
График синусоиды, построенный по пикселям (а) и линиями (б) а)  
 б)  


Канва — объект класса TCanvas имеет множество методов, которые позволяют рисовать графики, линии, фигуры с помощью свойства Pen — перо. Это свойство является объектом, в свою очередь имеющим ряд свойств. Одно из них уже известное вам свойство Color — цвет, которым наносится рисунок. Второе свойство — Width (ширина линии). Ширина задается в пикселях. По умолчанию ширина равна 1.

Свойство Style определяет вид линии. Это свойство может принимать следующие значения:


--------------------------------------------------------------------------------
psSolid Сплошная линия  
psDash Штриховая линия  
psDot Пунктирная линия  
psDashDot Штрих-пунктирная линия  
psDashDotDot Линия, чередующая штрих и два пунктира  
psClear Отсутствие линии  
psInsideFrame Сплошная линия, но при Width > 1 допускающая цвета, отличные от палитры Windows  

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

У канвы имеется свойство PenPos типа TPoint (см.). Это свойство определяет в координатах канвы текущую позицию пера. Перемещение пера без прорисовки линии, т.е. изменение PenPos, производится методом канвы MoveTo(X,Y). Здесь (X, Y) — координаты точки, в которую перемещается перо. Эта текущая точка становится исходной, от которой методом LineTo(X,Y) можно провести линию в точку с координатами (X,Y). При этом текущая точка перемещается в конечную точку линии и новый вызов LineTo будет проводить точку из этой новой текущей точки.

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

procedure TForm1.FormPaint(Sender: TObject);
var
 X,Y: real;      //   координаты  функции
 PX,PY: longint; //   координаты  пикселей
begin
 Color:=clWhite;
 Canvas.MoveTo(0,ClientHeight div 2);
 for PX:=0 to ClientWidth do
  begin
   {X - аргумент графика,
    соответствующий пикселю с координатой РХ}
   X := PX*4*Pi/ClientWidth;
   Y := Sin(X);
   {PY — координата пикселя,
    соответствующая координате Y}
   PY := trunc(ClientHeight - (Y+1)*ClientHeight/2);
   {Проводится линия на  графике}
   Canvas.LineTo(PX,PY);
  end;
end;

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

Перо может рисовать не только прямые линии, но и фигуры. Полный список методов канвы, использующих перо, см. во встроенной справке Delphi. А пока в качестве примера приведем только один из них — Ellipse, который рисует эллипс или окружность. Он объявлен как

procedure Ellipse(X1, Y1, Х2, Y2: Integer);

где параметры X1, Х2, Y1, Y2 определяют координаты прямоугольника, описывающего эллипс или окружность. Например, оператор
Canvas.Ellipse(10, 40, 20, 50);

нарисует окружность с диаметром 10 и с координатами центра (15, 45).
Фигуры в общем случае рисуются не пустыми, а закрашенными с помощью свойства канвы Brush — кисть. Свойство Brush является объектом, имеющим в свою очередь ряд свойств. Свойство Color определяет цвет заполнения. Свойство Style определяет шаблон заполнения (штриховку). По умолчанию значение Style равно bsSolid, что означает сплошное закрашивание цветом Color.

У пера Pen имеется еще одно свойство, которое мы пока не рассматривали. Это свойство — Mode (режим). По умолчанию значение Mode = pmCopy. Это означает, что линии проводятся цветом, заданным в свойстве Color. Но возможны и другие режимы, в которых учитывается не только цвет Color, но и цвет соответствующих пикселей фона. Наиболее интересным из этих режимов является режим pmNotXor — сложение с фоном по инверсному исключающему ИЛИ. Если задан этот режим, то повторное рисование той же фигуры на том же месте канвы убирает ранее нарисованное изображение и восстанавливает цвета пикселей, которые были до первого изображения фигуры.

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

Попробуйте сделать сами простенькую мультипликацию — движущуюся окружность. Начните новое приложение и в раздел implementation вставьте объявление

var X,Y: integer;

Тем самым вы введете глобальные переменные X и Y — текущие координаты изображения.

В событие формы OnPaint вставьте операторы

Canvas.Brush.Color := clWhite;
Color := clWhite;
Canvas.Pen.Mode := pmNotXor;

Первый из этих операторов задает белый цвет кисти Brush. Значит ваша окружность будет закрашена внутри белым цветом. Второй оператор задает белый цвет фона поверхности формы. Третий оператор устанавливает режим пера pmNotXor, который позволит вам стирать прежнее изображение прежде, чем нарисовать новое.

Даже самая простая мультипликация нуждается в синхронизации. Иначе скорость движения будет определяться быстродействием компьютера. Поэтому перенесите на форму компонент Timer — таймер со страницы System. Этот компонент описан в разделе 5.7. Можете посмотреть там его подробное описание. А пока задайте его свойство Interval равным, например, 30 (это время выдержки в миллисекундах, но реальное время выдержки будет больше — см. раздел 5.7) и установите свойство Enabled равным false (это означает, что таймер не будет запускаться автоматически в момент запуска приложения).

В обработчик события этого компонента OnTimer вставьте операторы

// Стирание прежнего изображения
Canvas.Ellipse(Х-5, Y, X+5, Y-1Q);
Inc(X);
// Рисование  нового изображения
Canvas.Ellipse(Х-5, Y, X+5, Y-10);
// Останов при достижении конца формы
if (X >= ClientWidth-20) then
  Timer1.Enabled := false;

Первый из этих операторов рисует окружность в том месте, где она была нарисована ранее, т.е. стирает прежнее изображение. Далее увеличивается на единицу функцией Inc текущая координата X и изображение окружности рисуется в новой позиции. Последний оператор останавливает изображение у края формы.

Теперь перенесите на форму кнопку Button и в обработчик щелчка на ней поместите операторы

Х:=10;
Y:=100;
Canvas.Ellipse(X-5, Y, X+5, Y-10);
Timer1.Enabled:=true;

Первые два оператора задают начальные координаты окружности. Третий оператор рисует окружность в ее начальном положении, а четвертый — запускает таймер.

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

На канве можно отображать не только программно создаваемые изображения, но и изображения, хранящиеся в графических файлах. Только сама канва не имеет метода загрузки изображения из файла. Поэтому загружать файл надо в какой-нибудь другой графический объект, способный воспринимать информацию графических файлов. А затем переписывать изображение из этого объекта на канву с помощью метода канвы Draw. Его описание:

procedure Draw(X, Y: Integer; Graphic: TGraphic);

Здесь параметры Х и Y определяют координаты левого верхнего угла размещения изображения на канве, a Graphic — объект, хранящий информацию. В качестве такого объекта может выступать, например, объект типа TBitMap, предназначенный для хранения битовых матриц. Давайте посмотрим, как все это выглядит на практике.

Откройте новое приложение, перенесите на форму компонент OpenPictureDialog со страницы Dialogs (это компонент диалога открытия графических файлов — см. раздел 8.2) и кнопку Button. Разместите OpenPictureDialog в любом месте формы, так как этот компонент невизуальный, а кнопку разместите внизу формы. В обработчик щелчка на кнопке занесите код:

procedure TForm1.Button1Click(Sender: TObject);
var
  BitMap:TBitMap;
begin
 //  Выбор  пользователем графического  файла
 if OpenPictureDialog1.Execute then
  begin
   // Создание объекта BitMap типа TBitMap
   BitMap:=TBitMap.Create;
   // Загрузка в BitMap выбранного графического файла
   BitMap.LoadFromFile(OpenPictureDialog1.FileName);
   // Перенос изображения на канву формы
   Canvas.Draw(10, 10, BitMap);
   // Уничтожение объекта BitMap
   BitMap.Free;
  end;
end;

Этот код создает временный объект типа TBitMap с именем BitMap. Затем вызывается диалог открытия графического файла OpenPictureDialog1 и, если пользователь выбрал файл, то он загружается в BitMap методом LoadFromFile. Затем методом Draw загруженное изображение копируется на канву в область, с координатами левого верхнего угла (10, 10). После этого временный объект BitMap уничтожается.

Запустите ваше приложение и щелкните на его кнопке. Вы увидите, что можете загрузить любой графический файл типа .bmp и он отобразится на канве формы (см. рис. 4.2 а). Графические файлы вы можете найти в каталоге Images. В Delphi 5 и 4 он обычно расположен в каталоге ...\program files\Common Files\Borland Shared. В Delphi 3 он расположен в каталоге ...\program files\Borland\Delphi 3, а в Delphi 1 — в каталоге Delphi 16. В каталоге Images имеется, в частности, подкаталог \Images\Splash\16Color\, в котором хранится файл, загруженный в примере рис. 4.2.

Рис. 4.2

Изображение на канве графического файла (а) и его стирание (б) при перекрытии другим окном
 а)  
 б)  


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

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

Если окно было перекрыто и изображение испортилось, операционная система сообщает приложению, что в окружении что-то изменилось и что приложение должно предпринять соответствующие действия. Как только требуется обновление окна, для него генерируется событие OnPaint. В обработчике этого события (в нашем случае события формы) нужно перерисовать изображение.

Перерисовка может производиться разными способами в зависимости от приложения. В нашем примере можно было бы вынести объявление переменной BitMap (оператор var BitMap: TBitMap) за пределы приведенной выше процедуры, т.е. сделать эту переменную глобальной, разместив непосредственно в разделе implementation. Оператор BitMap.Free можно было бы перенести в обработчик события формы OnDestroy, происходящего в момент закрытия приложения. Тогда в течение всего времени выполнения вашего приложения вы будете иметь копию картинки в компоненте BitMap и вам достаточно ввести в обработчик события OnPaint формы всего один оператор:

Canvas.Draw(10, 10, BitMap);

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

Помимо рассмотренного метода Draw канва имеет еще метод копирования CopyRect:

procedure CopyRect(Dest: TRect; Canvas: TCanvas; Source: TRect);

Метод копирует указанную параметром Source область изображения в канве источника изображения Canvas в указанную параметром Dest область данной канвы. Тип TRect, характеризующий прямоугольные области Source и Dest, уже описывался в разделе 3.2. Например, оператор

Canvas.CopyRect(MyRect2, Bitmap.Canvas, MyRect1);

копирует на канву формы в область MyRect2 изображение из области MyRect1 канвы компонента Bitmap.
Копирование методом CopyRect производится в режиме, установленном свойством CopyMode. По умолчанию это свойство имеет значение cmSrcCopy, что означает просто замену изображения, содержащегося ранее в области Dest, на копируемое изображение. Другие возможные значения CopyMode позволяют комбинировать изображения, но их рассмотрение выходит за рамки данной книги.

Оффлайн Zephyr

  • Пользователь
  • Сообщений: 544
  • Пол: Мужской
  • coder
    • Просмотр профиля
Delphi (TImage)
« Ответ #3 : 18 Октябрь 2007, 18:55:53 »
4.3 Компоненты Image и PaintBox
Компоненты Image и PaintBox представляют собой некоторую ограниченную поверхность с канвой, на которую можно заносить изображения, как это описано в разделе 4.2. При этом компонент PaintBox, собственно говоря, не дает ничего нового по сравнению с рисованием на канве формы. Рисование на PaintBox вместо формы не имеет никаких преимуществ, кроме, может быть, некоторого облегчения в расположении одного или нескольких рисунков в площади окна.

Компонент Image много богаче по своим возможностям и удобнее, чем PaintBox. Даже при использовании описанных в разделе 4.2 приемов рисования на канве компонент Image имеет существенное преимущество: в нем не приходится думать о перерисовке изображения, испорченного из-за перекрытия данного окна другими. Все, связанное с обработкой событий OnPaint, рассмотренных в разделе 4.2, в Image осуществляется автоматически. Кроме того с помощью Image проще, чем при непосредственном рисовании на канве формы, расположить в окне приложения несколько изображений и управлять ими. При этом отпадает необходимость сложных и нудных расчетов координат канвы формы, обеспечивающих требуемое взаимное расположение изображений, т.е. в полной мере проявляются преимущества визуального программирования. Так что, вероятно, во всех случаях лучше работать с канвой Image, чем с канвой формы.

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

Delphi поддерживает три типа файлов — битовые матрицы, пиктограммы и метафайлы. Все три типа файлов хранят изображения; различие заключается лишь в способе их хранения внутри файлов и в средствах доступа к ним. Битовая матрица (файл с расширением .bmp) отображает цвет каждого пикселя в изображении. При этом информация хранится таким образом, что любой компьютер может отобразить изображение с разрешающей способностью и количеством цветов, соответствующими его конфигурации.

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

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

Компонент Image позволяет отображать информацию, содержащуюся в графических файлах всех указанных типов. Для этого служит его свойство Picture — объект типа TPicture.

Рис. 4.3
Окно Picture Editor  


Чтобы познакомиться с этим свойством откройте новое приложение и перенесите на форму компонент Image. Растяните его или задайте его свойство Align равным alClient, чтобы он занял всю клиентскую область формы. Нажмите на кнопку с многоточием около свойства Picture в окне Инспектора Объектов или просто сделайте двойной щелчок на Image. Перед вами откроется окно Picture Editor (рис. 4.3), позволяющее загрузить в свойство Picture какой-нибудь графический файл (кнопка Load), а также сохранить открытый файл под новым именем или в новом каталоге. Щелкните на Load, чтобы загрузить графический файл. Перед вами откроется окно открытия графического файла, представленное на рис. 4.4. По мере перемещения курсора в списке по графическим файлам в правом окне отображаются содержащиеся в них картинки, а над ними — цифры, характеризующие размер картинки. Вы можете выбрать требуемый вам графический файл любого типа. Напомним, что поставляемые с Delphi графические файлы вы можете найти в каталоге Images. В Delphi 5 и 4 он обычно расположен в каталоге ...\program files\Common Files\Borland Shared. В Delphi 3 он расположен в каталоге ...\program files\Borland\Delphi 3, а в Delphi 1 — в каталоге Delphi 16. После загрузки файла щелкните на OK в окне Picture Editor и в вашем компоненте Image отобразится выбранная вами картинка. Можете запустить ваше приложение и полюбоваться ею. Впрочем, вы и так видите картинку, даже не выполняя приложение.

Рис. 4.4
Окно диалога открытия графического файла  
 


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

Вернемся к рассмотрению свойств компонента Image.

Если установить свойство AutoSize в true, то размер компонента Image будет автоматически подгоняться под размер помещенной в него картинки. Если же свойство AutoSize установлено в false, то изображение может не поместиться в компонент или, наоборот, площадь компонента может оказаться много больше площади изображения.

Другое свойство — Stretch позволяет подгонять не компонент под размер рисунка, а рисунок под размер компонента. Установите AutoSize в false, растяните или сожмите размер компонента Image и установите Stretch в true. Вы увидите, что рисунок займет всю площадь компонента, но поскольку вряд ли реально установить размеры Image точно пропорциональными размеру рисунка, то изображение исказится. Устанавливать Stretch в true может иметь смысл только для каких-то узоров, но не для картинок. Свойство Stretch не действует на изображения пиктограмм, которые не могут изменять своих размеров.

Свойство — Center, установленное в true, центрирует изображение на площади Image, если размер компонента больше размера рисунка.

Рассмотрим еще одно свойство — Transparent (прозрачность). Если Transparent равно true, то изображение в Image становится прозрачным. Это можно использовать для наложения изображений друг на друга. Поместите на форму второй компонент Image и загрузите в него другую картинку. Только постарайтесь взять какую-нибудь мало заполненную, контурную картинку. Можете, например, взять картинку из числа помещаемых обычно на кнопки, например, стрелку (файл ...\program files\common files\borland shared\images\buttons\arrow1l.bmp). Передвиньте ваши Image так, чтобы они перекрывали друг друга, и в верхнем компоненте установите Transparent равным true. Вы увидите, что верхняя картинка перестала заслонять нижнюю. Одно из возможных применений этого свойства — наложение на картинку надписей, выполненных в виде битовой матрицы. Эти надписи можно сделать с помощью встроенной в Delphi программы Image Editor.

Учтите, что свойство Transparent действует только на битовые матрицы. При этом прозрачным (т.е. заменяемым на цвет расположенного под ним изображения) делается по умолчанию цвет левого нижнего пикселя битовой матрицы.

Мы рассмотрели загрузку изображения из файла в процессе проектирования. Но свойство Picture позволяет также легко организовать обмен с графическими файлами любых типов в процессе выполнения приложения. Чтоб пояснить технику такого обмена, надо сначала подробнее рассмотреть свойство Picture.

Это свойство является объектом, который имеет в свою очередь подсвойства, указывающие на хранящийся графический объект. Если в Picture хранится битовая матрица, на нее указывает свойство Picture.Bitmap. Если хранится пиктограмма, на нее указывает свойство Picture.Icon. На хранящийся метафайл указывает свойство Picture.Metafile. Наконец, на графический объект произвольного типа указывает свойство Picture.Graphic.

Объект Picture и его свойства Bitmap, Icon, Metafile и Graphic имеют методы файлового чтения и записи LoadFromFile и SaveToFile:

procedure LoadFromFile(const FileName: string);
procedure SaveToFile(const FileName: string);

Для свойств Picture.Bitmap, Picture.Icon и Picture.Metafile формат файла должен соответствовать классу объекта: битовой матрице, пиктограмме, метафайлу. При чтении файла в свойство Picture.Graphiс файл должен иметь формат метафайла. А для самого объекта Picture методы чтения и записи автоматически подстраиваются под тип файла. Поясним это на примере.

Давайте построим приложение, аналогичное рассмотренному в разделе 4.2 примеру просмотра графических файлов. Для разнообразия можно организовать управление им не кнопкой Button, а меню. Поместите на форму компонент Image. Растяните его или задайте его свойство Align равным alClient, чтобы он занял всю клиентскую область формы. Перенесите на форму компонент диалога открытия графического файла OpenPictureDialog (см. раздел 8.2). Поместите также на форму компонент главного меню MainMenu (см. раздел 6.1) и задайте в нем один раздел — Файл. В обработчике этого раздела напишите оператор

if(OpenPictureDialog1.Execute) then
  Image1.Picture.LoadFromFile(
    OpenPictureDialog1.FileName);

Этот оператор вызовет диалог открытия графического файла (см. рис. 4.4) и загрузит в компонент Image1 изображение из выбранного пользователем файла (см. рис. 4.5). Причем файл может быть любого типа: битовая матрица, пиктограмма или метафайл.

Рис. 4.5
Изображение в компоненте Image битовой матрицы (а) и пиктограммы (6)  а)  б)  


В этом приложении метод LoadFromFile применен к Image1.Picture. Если будут открываться только файлы битовых матриц, то оператор загрузки файла можно заменить на

  Image1.Picture.Bitmap.LoadFromFile(
    OpenPictureDialog1.FileName);

Для пиктограмм можно было бы использовать оператор

  Image1.Picture.Icon.LoadFromFile(
    OpenPictureDialog1.FileName);

а для метафайлов — оператор
  Image1.Picture.Metafile.LoadFromFile(
    OpenPictureDialog1.FileName);

или
  Image1.Picture.Graphic.LoadFromFile(
    OpenPictureDialog1.FileName) ;

Но во всех этих случаях, если формат файла не совпадет с предполагаемым, возникнет ошибка. Аналогично работает и метод SaveToFile с тем отличием, что примененный к Picture или к Picture.Graphic он сохраняет в файле изображение любого формата. Например, если вы дополните свое приложение диалогом SavePictureDialog (см. раздел 8.2), введете в меню раздел Сохранить как и в его обработчик поместите оператор

if SavePictureDialog1.Execute then
  Image1.Picture.SaveToFile(SavePictureDialog1.FileName);

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

  Image1.Picture.Graphic.SaveToFile(
    SavePictrureDialog1.FileName);

использующий свойство Picture.Graphic. А если вам известен формат хранимого в компоненте Image изображения, то вы можете применить метод SaveToFile к свойствам Picture.Bitmap, Picture.Icon и Picture.Metafile.
Для всех рассмотренных объектов Picture, Picture.Bitmap, Picture.Icon и Picture.Metafile определены методы присваивания значений объектов:

procedure Assign(Source: TPersistent);

Однако, для BitMap, Icon и Metafile присваивать можно только значения однородных объектов: соответственно битовых матриц, пиктограмм, метафайлов. При попытке присвоить значения разнородных объектов генерируется исключение ЕConvertError. Объект Picture — универсальный, ему можно присваивать значения объектов любых из остальных трех классов. А значение Picture можно присваивать только тому объекту, тип которого совпадает с типом объекта, хранящегося в нем.

Метод Assign можно использовать и для обмена изображениями с буфером Clipboard. Например, оператор

Clipboard.Assign(Image1.Picture) ;

занесет в буфер обмена изображение, хранящееся в Image1. Аналогично оператор
Image1.Picture.Assign(Clipboard) ;

прочитает в Image1 изображение, находящееся в буфере обмена. Причем это может быть любое изображение и даже текст.
Надо только не забыть при работе с буфером обмена вставить в оператор uses вашего модуля ссылку на модуль Clipbrd. Автоматически Delphi эту ссылку не вставляет.

Возвращаясь к свойствам компонента Image, можно отметить один недостаток, присущий нашему тестовому приложению, приведенному на рис. 4.5. При загрузке разных изображений размер окна приложения может оказаться или слишком маленьким, и тогда вы увидите только часть изображения, или слишком большим, и тогда изображение будет некрасиво размещено в левом верхнем углу формы, оставляя много пустого пространства. Этот недостаток можно устранить, если воспользоваться свойствами Height (высота) и Width (ширина) компонента Image. При свойстве AutoSize установленном в true размеры Image автоматически устанавливаются равными размерам загруженного изображения. И этими размерами можно воспользоваться для соответствующего изменения размеров формы. Например, приведенный ранее код загрузки изображения из файла можно заменить на следующий:

if OpenPictureDialog1.Execute then
 begin
  Image1.Picture.LoadFromFile(
   OpenPictureDialog1.FileName);
  Form1.ClientHeight := Image1.Height+10;
  Image1.Top := Form1.ClientRect.Top
   + (Form1.ClientHeight - Image1.Height) div 2;
  Form1.ClientWidth := Image1.Width+10;
  Image1.Left := Form1.ClientRect.Left
   + (Form1.ClientWidth - Image1.Width) div 2;
 end;

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

Оффлайн Zephyr

  • Пользователь
  • Сообщений: 544
  • Пол: Мужской
  • coder
    • Просмотр профиля
Delphi (TImage)
« Ответ #4 : 18 Октябрь 2007, 18:58:28 »
GDI - графика в Delphi
 Previous  Top  Next  


     
 


 

 

Автор: Alistair Keys

 

Жаргон GDI.

 

GDI расшифровывается как Graphics Device Interface, и представляет собой интерфейс, который Windows использует для рисования 2D графики. Также это самый медленный способ отображения графики из существующих, однако самый простой для понимания основ. Итак, для начала, поговорим об основных понятиях и терминах в GDI.

 

Начнём с того, что GDI обычно не используют для создания крутых графических эффектов, для этого есть DirectX, OpenGL, или любые графические библиотеки (такие как: DelphiX, FastLib, DIBUltra, Graphics32...). Однако, для создание простых эффектов с минимальными усилиями GDI вполне сгодится.

 

С GDI тесно связана ещё одна аббревиатура - DC ("Device Context" - контекст устройства). Это то, на чём мы рисуем, и в Delphi контекст устройства представлен как TCanvas. Идея контекста устройства заключается в том, что это универсальное устройство вывода, поэтому можно использовать одинаковые функции как для экрана, так и для принтера.

 

Все графические функции в Delphi являются надстройками над стандартными GDI функциями Windows. Позже мы поговорим об этих функциях.

 

А теперь самое время приступить к рассмотрению того, как устроен GDI. Ниже, в таблице, представлены некоторые важные классы:

 

 

Pen Используется для рисования простых линий. Обычно применяется для функции LineTo или при рисовании рамки для определённой фигуры (например для функции Rectangle).

 

Brush Кисть используется для заполнения области определённым цветом. Применяется в функциях Rectangle, FillRect или FloodFill.

 

Font Используется для задания шрифта, которым будет нарисован текст. Можно указать имя шрифта, размер и т.д.

 

Region Позволяет задать регион (замкнутое пространство). Регионом может быть круг, квадрат или произвольная фигура. Позволяет так же делать дырки в фигурах.

 

Однако, пора переходить от слов к делу, а именно, начать рисовать линии и фигуры.

 

Рисование линий

 

Сперва необходимо чётко уяснить, что координата (0,0) это верхний левый угол экрана. То есть значения по оси y увеличиваются вниз экрана. Соответственно, координата (0, 50) означает, что мы просто отступили на 50 пикселей от верха экрана.

 

Самое главное, что надо знать при рисовании линий и фигур, это различие между пером (Pen) и кистью (Brush). Всё очень просто: перо (Pen) используется при рисовании линий или рамок, а кисть (Brush) для заполнения фигуры.

 

Ниже приведены две функции, которые используются для рисования линий и обе принадлежат TCanvas:

 

MoveTo Перемещает точку начала рисования линии в указанные координаты x и y Canvas.MoveTo(50, 100);

 

LineTo Рисует линию начиная с текущей позиции (см. MoveTo) до указанных координат x и y. Canvas.LineTo(50, 100);

 

Эффект перемещения точки начала рисования линии так же достигается при помощи установки своства PenPos в канвасе... например, "Canvas.PenPos.x := 20;", "Canvas.PenPos.y := 50", или "Canvas.PenPos := Point(20,50);".

 

По умолчанию, точка начала рисования установлена в (0,0), то есть, если сразу вызвать "Canvas.LineTo(100,100);" то будет нарисована линия из точки (0,0) в точку (100, 100). Точка начала рисования автоматически переместится в (100, 100), то есть, если выполнить команду "Canvas.LineTo(200, 100);", то следующая линия будет нарисована из точки (100, 100) в (200, 100). Поэтому, если мы хотим рисовать линии несоединённые друг с другом, то придётся воспользоваться методом MoveTo.

 

Линия, нарисованная при помощи LineTo использует текущее перо канваса (типа TPen). Основные свойства пера, это ширина - "Canvas.Pen.Width := 4;" (при помощи которого можно задавать различную ширину линий), и цвет "Canvas.Pen.Color := clLime;".

 

Взглянем на простой пример беспорядочного рисования разноцветных линий:

Code:
 
procedure TForm1.FormCreate(Sender: TObject);

begin

// инициализируем генератор

// случайных чисел

Randomize;

end;

 

const

NUM_LINES = 2000;

 

procedure TForm1.DrawLines;

var

i: Integer;

begin

for i := 0 to NUM_LINES - 1 do

begin

   Canvas.Pen.Color :=

     RGB(Random(256),

     Random(256),

     Random(256));

   Canvas.LineTo

     (Random(ClientWidth),

     Random(ClientHeight));

end;

end;
 

 

 

 

 

 

 

Процедура DrawLines вызывается из обработчика кнопки OnClick. Количество линий задаётся в константе NUM_LINES. Между прочим, функция RGB, составляет цвет каждой линии из трёх основных составляющих: красного, зелёного и синего (значения от 0 до 255) и возвращает нам цвет в виде TColor.

 

 

Рисование фигур

 

Для рисования фигур, в TCanvas предусмотрены следующие функции:

 

Ellipse Рисует элипс, вписанный в невидимый квадрат с координатами верхнего левого угла и правого нижнего. Если координаты х и y у углов будут совпадать, то получится круг. Canvas.Ellipse(0,0,50,50);

 

FillRect Заполняет прямоугольник цветом текущей кисти (brush), но никак не за пределами него. Canvas.FillRect( Bounds(0,0,100,100));

 

FloodFill Заполняет данную область цветом текущей кисти, до тех пор пока не будет достигнут край. Canvas.FloodFill(10, 10, clBlack, fsBorder);

 

Rectangle Рисует прямоугольник (или квадрат), заполненный цветом текущей кисти и обрамлённый цветом текущего пера Canvas.Rectangle( Bounds(20, 20, 50, 50));

 

RoundRect Тоже, что и Rectangle, но с загруглёнными углами. Canvas.RoundRect( 20, 20, 50, 50, 3, 3);

 

 

Ещё есть очень нужная функция TextOut, которая позволяет рисовать текст, используя шрифт, заданный в канвасе:

 

TextOut Рисует данную строку на канвасе начиная с координат (x,y) - фон текста заполняется текущим цветом кисти. Canvas.TextOut(10, 10, 'Some text');

 

Кстати, функция позволяет рисовать текст, не заполняя его фон. Если Вам необходимо изменить шрифт, используемый в TextOut, то необходимо изменить свойство Font канваса (это свойство имеет тип TFont) - например "Canvas.Font.Name := 'Verdana';", "Canvas.Font.Size := 24;" или "Canvas.Font.Color := clRed;".

 

Вкратце хотелось бы обратить Ваше внимание на довольно полезный класс TRect, который умеет хранить в себе значения лево, право, верха и низа (кстати, в Windows API это RECT). То ест, достаточно указать левую и верхнюю координату и ширину и высоту области, а TRect автоматически подставит в виде (лево, верх, лево + ширина, верх + высота). Ещё есть другая функция Rect(), которая делает тоже самое, но координаты в ней задаются напрямую как лево, право, верх и низ. Ну и по желанию, можно использовать API функцию SetRect.

 

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

Code:
 
const

NUM_SHAPES = 200;

 

procedure TForm1.DrawShapes;

var

i, ShapeLeft, ShapeTop: Integer;

begin

for i := 0 to NUM_SHAPES - 1 do

begin

   Canvas.Brush.Color :=

     RGB(Random(256),

     Random(256),

     Random(256));

   ShapeLeft := Random(ClientWidth);

   ShapeTop := Random(ClientHeight);

   // теперь, случайным образом, решаем что рисовать

   case Random(3) of

     0: Canvas.Rectangle(ShapeLeft,

         ShapeTop,

         ShapeLeft + Random(50),

         ShapeTop + Random(50));

     1: Canvas.Ellipse(ShapeLeft,

         ShapeTop,

         ShapeLeft + Random(50),

         ShapeTop + Random(50));

     2:

       begin

         Canvas.Font.Size := 10 + Random(7); // от 10 до 16

         Canvas.TextOut(ShapeLeft, ShapeTop, 'Some text');

       end;

   end;

end;

end;
 

 

 

Как Вы уже успели заметить, некоторые фигурки имеют цвет рамки, отличающийся от того цвета, которым заполнена фигура. Это как раз тот момент, о котором я упоминал выше. Кистью мы заполняем объекты, а пером обрамляем. Если цвет кисти (brush) меняется случайным образом, то цвет пера(pen) остаётся постоянным. Из-за этого и получается такая картина.

 

Перерисовка окна

 

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

 

Рисование, это то, что мы делали выше. То есть, рисовали любые линии и графические фигуры. Однако, рисунок сохранялся до тех пор, пока окно(форма) не было обновлено.

 

Перерисовка несколько отличается от понятия "рисование". Когда окну необходимо перерисоваться, то Windows посылает определённое сообщение. Это сообщение поступает в обработчик события "OnPaint". Любой код, который поместить в обработчик OnPaint будет вызван каждый раз, когда форме необходимо обновиться.

 

Для примера, поместите следующий код в проект:

Code:
 
procedure TForm1.DrawSomeText;

begin

Canvas.TextOut(10, 10, 'Some text');

end;
 

 

Если поместить на форму кнопку и вызывать DrawSomeText из обработчика кнопки OnClick, то проблема с исчезновением текста при перемещении формы останется. ОДНАКО, если вызвать DrawSomeText из обработчика формы OnPaint, то текст останется на своём месте окончательно.

 

Дескрипторы, или как пользоваться аналогичными API функциями

 

Итак, мы научились рисовать линии, различные фигуры, научились делать так, чтобы наше творение не стиралось при перемещении формы, и проделали мы всё это при помощи стандартных функций VCL (таких как Canvas.TextOut и т.д.). Однако, что делать, если Вы не хотите пользоваться графическими функциями VCL, которые всего навсего являются надстройками над аналогичными функциями из Windows API? Пожалуйста! Никто нам не запрещает пользоваться API функциями напрямую! Но постойте-ка, все они требуют какого-то HDC! Что такое HDC?

 

Почти всё в Windows использует "Дескриптор" (Handle). Дескриптор, это способ идентификации Вашего объекта в системе. У каждого окна есть свой дескриптор, у каждой кнопки тоже есть свой дескриптор и т.д. Именно поэтому все наши объекты имеют дескриптор в качестве свойства - например, "MyForm.Canvas.Handle".

 

Тип HDC это Дескриптор(Handle) Контекста Устройства (Device Context). Я уже говорил в самом начале, что TCanvas включает в себя большинство функций DC. Поэтому, мы спокойно можем подставлять свойство канваса Handle везде, где нам это потребуется.

 

Ради интереса можно взглянуть на таблицу, в которой представлены примеры вызовов некоторых функций из VCL и их аналогов из Windows API.

 

Canvas.TextOut(x,y,myString);                TextOut(Canvas.Handle, x, y, PChar(myString), Length(String));

 

Canvas.FloodFill(X, Y, Color,fsBorder);        ExtFloodFill(Canvas.Handle, x, y, YourColour, FLOODFILLBORDER);

 

Canvas.LineTo(x,y);                                LineTo(Canvas.Handle, x, y);

 

Canvas.MoveTo(x,y);                                MoveToEx(Canvas.Handle, x, y, nil);

 

Так же можно использовать разные дескрипторы, чтобы рисовать в разных местах. Например, можно использовать "SomeBmp.Canvas.Handle" для рисования на картинке (битмапе), либо "Form1.Canvas.Handle", чтобы рисовать на форме.

 

В API версии функции TextOut необходимо передавать строку завершённую нулём. Это значит, что вместо того, чтобы передать строку в функцию напрямую, необходимо передать её как PChar. Так же не забывайте передавать в функцию длину строки. Для этого можно воспользоваться функцией Length.

 

Ну что, Вам уже захотелось поместить на форму какую-нибудь красивую картинку ?

 

Что такое Битмапы (Bitmaps)?

 

Рисование линий, это, конечно, хорошо, но рано или поздно Вам понадобится нарисовать более реалистичную картнику в своём приложении. Поэтому совершенно необходимо научиться работать с растровыми изображениями, или как их называют в среде программистов - битмапами.

 

Битмап, это графический объект, который содержит заголовок, необходимую информацию о картинке (такую как высота, ширина, цвета и т.д.) и, собственно, само изображение (большой массив, содержащий цвет каждой точки). В Delphi для этой цели уже предусмотрен класс TBitmap.

 

Битмапы можно рисовать не только на форме, но и по всему экрану. Может это и может показаться немного странным, но иногда это бывает полезно, особенно при создании скринсейвера. Однако, сначала нам необходимо разобраться с тем, как работать с битмапами. Вот небольшой пример:

Code:
 
procedure Form1.DrawBitmap(const Filename: string; const x, y: Integer);

var

Bmp: TBitmap;

begin

// Сперва убедимся, что файл существует!

if not FileExists(Filename) then

begin

   ShowMessage('The bitmap ' + Filename + ' was not found!');

   Exit;

end;

 

Bmp := TBitmap.Create;

try

   Bmp.LoadFromFile(Filename);

   Canvas.Draw(x, y, Bmp);

finally

   Bmp.Free;

end;

end;
 

 

 

 

 

 

 

Эта функция пытается загрузить и показать картинку, (с именем Filename, например 'myBitmap.bmp') начиная с точки (x,y).

 

Сразу скажу, что эта функция довольно неэффективна. Она создаёт и уничтожает битмап каждый раз когда вызывается, а так же каждый раз проверяет существование файла. Лучше объявлять объект TBitmap как часть формы, создавать и загружать картинку в FormCreate, а освобождать её в FormDestroy.

 

Функции рисования в GDI

 

TCanvas имеет несколько полезных функций, которые работают с типом TGraphic. Тип TGraphic является базовым классом для графических объектов в Delphi, таких как: битмапы (TBitmap), иконки (TIcon), метафайлы (TMetafile) и JPEG-и (TJPEGImage). Все они используют одни и те же функции, которые приведены в таблице:

 

Все эти функции являются методами TCanvas.

 

Draw Рисует TGraphic на канвасе так как он есть, не растягивая. Canvas.Draw(5,10,MyGraphic);

 

StrechDraw Рисует TGraphic на канвасе, подгоняя (растягивая) его под заданную область. Canvas.StretchDraw( Bounds(0,0,32,32), MyGraphic);

 

CopyRect Копирует часть TCanvas-а в другой, при необходимости растягивая его. Canvas.CopyRect( Bounds(0,0,32,32), MyBmp.Canvas, Bounds(0, 0, 640, 480));

 

TCanvas.Draw является обёрткой для API функции BitBlt:

 

function BitBlt(

hdcDest: HDC; // дескриптор конечного контекста устройства

nXDest, // коорд. x верхнего левого угла конечного прямоугольника

nYDest, // коорд. y верхнего левого угла конечного прямоугольника

nWidth, // ширина конечного прямоугольника

nHeight: Integer; // высота конечного прямоугольника

hdcSrc: HDC; // дескриптор исходного контекста устройства

nXSrc, // коорд. x верхнего левого угла исходного прямоугольника

nYSrc: Integer; // коорд. y верхнего левого угла исходного прямоугольника

dwRop: DWORD // код растровой операции

): Boolean;

Оффлайн Acider

  • Пользователь
  • Сообщений: 237
    • Просмотр профиля
Re: Delphi (TImage)
« Ответ #5 : 24 Октябрь 2007, 11:13:26 »
А чем тебя правый клик по Image3, Control->Send to back не устраивает?
Спасибо.

Добавлено позже:
4.3 Компоненты Image и PaintBox
Компоненты Image и PaintBox представляют собой некоторую ограниченную поверхность с канвой, на которую можно заносить изображения, как это описано в разделе 4.2. При этом компонент PaintBox, собственно говоря, не дает ничего нового по сравнению с рисованием на канве формы. Рисование на PaintBox вместо формы не имеет никаких преимуществ, кроме, может быть, некоторого облегчения в расположении одного или нескольких рисунков в площади окна.

Компонент Image много богаче по своим возможностям и удобнее, чем PaintBox. Даже при использовании описанных в разделе 4.2 приемов рисования на канве компонент Image имеет существенное преимущество: в нем не приходится думать о перерисовке изображения, испорченного из-за перекрытия данного окна другими. Все, связанное с обработкой событий OnPaint, рассмотренных в разделе 4.2, в Image осуществляется автоматически. Кроме того с помощью Image проще, чем при непосредственном рисовании на канве формы, расположить в окне приложения несколько изображений и управлять ими. При этом отпадает необходимость сложных и нудных расчетов координат канвы формы, обеспечивающих требуемое взаимное расположение изображений, т.е. в полной мере проявляются преимущества визуального программирования. Так что, вероятно, во всех случаях лучше работать с канвой Image, чем с канвой формы.

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

Delphi поддерживает три типа файлов — битовые матрицы, пиктограммы и метафайлы. Все три типа файлов хранят изображения; различие заключается лишь в способе их хранения внутри файлов и в средствах доступа к ним. Битовая матрица (файл с расширением .bmp) отображает цвет каждого пикселя в изображении. При этом информация хранится таким образом, что любой компьютер может отобразить изображение с разрешающей способностью и количеством цветов, соответствующими его конфигурации.

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

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

Компонент Image позволяет отображать информацию, содержащуюся в графических файлах всех указанных типов. Для этого служит его свойство Picture — объект типа TPicture.

Рис. 4.3
Окно Picture Editor 


Чтобы познакомиться с этим свойством откройте новое приложение и перенесите на форму компонент Image. Растяните его или задайте его свойство Align равным alClient, чтобы он занял всю клиентскую область формы. Нажмите на кнопку с многоточием около свойства Picture в окне Инспектора Объектов или просто сделайте двойной щелчок на Image. Перед вами откроется окно Picture Editor (рис. 4.3), позволяющее загрузить в свойство Picture какой-нибудь графический файл (кнопка Load), а также сохранить открытый файл под новым именем или в новом каталоге. Щелкните на Load, чтобы загрузить графический файл. Перед вами откроется окно открытия графического файла, представленное на рис. 4.4. По мере перемещения курсора в списке по графическим файлам в правом окне отображаются содержащиеся в них картинки, а над ними — цифры, характеризующие размер картинки. Вы можете выбрать требуемый вам графический файл любого типа. Напомним, что поставляемые с Delphi графические файлы вы можете найти в каталоге Images. В Delphi 5 и 4 он обычно расположен в каталоге ...\program files\Common Files\Borland Shared. В Delphi 3 он расположен в каталоге ...\program files\Borland\Delphi 3, а в Delphi 1 — в каталоге Delphi 16. После загрузки файла щелкните на OK в окне Picture Editor и в вашем компоненте Image отобразится выбранная вами картинка. Можете запустить ваше приложение и полюбоваться ею. Впрочем, вы и так видите картинку, даже не выполняя приложение.

Рис. 4.4
Окно диалога открытия графического файла 
 


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

Вернемся к рассмотрению свойств компонента Image.

Если установить свойство AutoSize в true, то размер компонента Image будет автоматически подгоняться под размер помещенной в него картинки. Если же свойство AutoSize установлено в false, то изображение может не поместиться в компонент или, наоборот, площадь компонента может оказаться много больше площади изображения.

Другое свойство — Stretch позволяет подгонять не компонент под размер рисунка, а рисунок под размер компонента. Установите AutoSize в false, растяните или сожмите размер компонента Image и установите Stretch в true. Вы увидите, что рисунок займет всю площадь компонента, но поскольку вряд ли реально установить размеры Image точно пропорциональными размеру рисунка, то изображение исказится. Устанавливать Stretch в true может иметь смысл только для каких-то узоров, но не для картинок. Свойство Stretch не действует на изображения пиктограмм, которые не могут изменять своих размеров.

Свойство — Center, установленное в true, центрирует изображение на площади Image, если размер компонента больше размера рисунка.

Рассмотрим еще одно свойство — Transparent (прозрачность). Если Transparent равно true, то изображение в Image становится прозрачным. Это можно использовать для наложения изображений друг на друга. Поместите на форму второй компонент Image и загрузите в него другую картинку. Только постарайтесь взять какую-нибудь мало заполненную, контурную картинку. Можете, например, взять картинку из числа помещаемых обычно на кнопки, например, стрелку (файл ...\program files\common files\borland shared\images\buttons\arrow1l.bmp). Передвиньте ваши Image так, чтобы они перекрывали друг друга, и в верхнем компоненте установите Transparent равным true. Вы увидите, что верхняя картинка перестала заслонять нижнюю. Одно из возможных применений этого свойства — наложение на картинку надписей, выполненных в виде битовой матрицы. Эти надписи можно сделать с помощью встроенной в Delphi программы Image Editor.

Учтите, что свойство Transparent действует только на битовые матрицы. При этом прозрачным (т.е. заменяемым на цвет расположенного под ним изображения) делается по умолчанию цвет левого нижнего пикселя битовой матрицы.

Мы рассмотрели загрузку изображения из файла в процессе проектирования. Но свойство Picture позволяет также легко организовать обмен с графическими файлами любых типов в процессе выполнения приложения. Чтоб пояснить технику такого обмена, надо сначала подробнее рассмотреть свойство Picture.

Это свойство является объектом, который имеет в свою очередь подсвойства, указывающие на хранящийся графический объект. Если в Picture хранится битовая матрица, на нее указывает свойство Picture.Bitmap. Если хранится пиктограмма, на нее указывает свойство Picture.Icon. На хранящийся метафайл указывает свойство Picture.Metafile. Наконец, на графический объект произвольного типа указывает свойство Picture.Graphic.

Объект Picture и его свойства Bitmap, Icon, Metafile и Graphic имеют методы файлового чтения и записи LoadFromFile и SaveToFile:

procedure LoadFromFile(const FileName: string);
procedure SaveToFile(const FileName: string);

Для свойств Picture.Bitmap, Picture.Icon и Picture.Metafile формат файла должен соответствовать классу объекта: битовой матрице, пиктограмме, метафайлу. При чтении файла в свойство Picture.Graphiс файл должен иметь формат метафайла. А для самого объекта Picture методы чтения и записи автоматически подстраиваются под тип файла. Поясним это на примере.

Давайте построим приложение, аналогичное рассмотренному в разделе 4.2 примеру просмотра графических файлов. Для разнообразия можно организовать управление им не кнопкой Button, а меню. Поместите на форму компонент Image. Растяните его или задайте его свойство Align равным alClient, чтобы он занял всю клиентскую область формы. Перенесите на форму компонент диалога открытия графического файла OpenPictureDialog (см. раздел 8.2). Поместите также на форму компонент главного меню MainMenu (см. раздел 6.1) и задайте в нем один раздел — Файл. В обработчике этого раздела напишите оператор

if(OpenPictureDialog1.Execute) then
  Image1.Picture.LoadFromFile(
    OpenPictureDialog1.FileName);

Этот оператор вызовет диалог открытия графического файла (см. рис. 4.4) и загрузит в компонент Image1 изображение из выбранного пользователем файла (см. рис. 4.5). Причем файл может быть любого типа: битовая матрица, пиктограмма или метафайл.

Рис. 4.5
Изображение в компоненте Image битовой матрицы (а) и пиктограммы (6)  а)  б) 


В этом приложении метод LoadFromFile применен к Image1.Picture. Если будут открываться только файлы битовых матриц, то оператор загрузки файла можно заменить на

  Image1.Picture.Bitmap.LoadFromFile(
    OpenPictureDialog1.FileName);

Для пиктограмм можно было бы использовать оператор

  Image1.Picture.Icon.LoadFromFile(
    OpenPictureDialog1.FileName);

а для метафайлов — оператор
  Image1.Picture.Metafile.LoadFromFile(
    OpenPictureDialog1.FileName);

или
  Image1.Picture.Graphic.LoadFromFile(
    OpenPictureDialog1.FileName) ;

Но во всех этих случаях, если формат файла не совпадет с предполагаемым, возникнет ошибка. Аналогично работает и метод SaveToFile с тем отличием, что примененный к Picture или к Picture.Graphic он сохраняет в файле изображение любого формата. Например, если вы дополните свое приложение диалогом SavePictureDialog (см. раздел 8.2), введете в меню раздел Сохранить как и в его обработчик поместите оператор

if SavePictureDialog1.Execute then
  Image1.Picture.SaveToFile(SavePictureDialog1.FileName);

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

  Image1.Picture.Graphic.SaveToFile(
    SavePictrureDialog1.FileName);

использующий свойство Picture.Graphic. А если вам известен формат хранимого в компоненте Image изображения, то вы можете применить метод SaveToFile к свойствам Picture.Bitmap, Picture.Icon и Picture.Metafile.
Для всех рассмотренных объектов Picture, Picture.Bitmap, Picture.Icon и Picture.Metafile определены методы присваивания значений объектов:

procedure Assign(Source: TPersistent);

Однако, для BitMap, Icon и Metafile присваивать можно только значения однородных объектов: соответственно битовых матриц, пиктограмм, метафайлов. При попытке присвоить значения разнородных объектов генерируется исключение ЕConvertError. Объект Picture — универсальный, ему можно присваивать значения объектов любых из остальных трех классов. А значение Picture можно присваивать только тому объекту, тип которого совпадает с типом объекта, хранящегося в нем.

Метод Assign можно использовать и для обмена изображениями с буфером Clipboard. Например, оператор

Clipboard.Assign(Image1.Picture) ;

занесет в буфер обмена изображение, хранящееся в Image1. Аналогично оператор
Image1.Picture.Assign(Clipboard) ;

прочитает в Image1 изображение, находящееся в буфере обмена. Причем это может быть любое изображение и даже текст.
Надо только не забыть при работе с буфером обмена вставить в оператор uses вашего модуля ссылку на модуль Clipbrd. Автоматически Delphi эту ссылку не вставляет.

Возвращаясь к свойствам компонента Image, можно отметить один недостаток, присущий нашему тестовому приложению, приведенному на рис. 4.5. При загрузке разных изображений размер окна приложения может оказаться или слишком маленьким, и тогда вы увидите только часть изображения, или слишком большим, и тогда изображение будет некрасиво размещено в левом верхнем углу формы, оставляя много пустого пространства. Этот недостаток можно устранить, если воспользоваться свойствами Height (высота) и Width (ширина) компонента Image. При свойстве AutoSize установленном в true размеры Image автоматически устанавливаются равными размерам загруженного изображения. И этими размерами можно воспользоваться для соответствующего изменения размеров формы. Например, приведенный ранее код загрузки изображения из файла можно заменить на следующий:

if OpenPictureDialog1.Execute then
 begin
  Image1.Picture.LoadFromFile(
   OpenPictureDialog1.FileName);
  Form1.ClientHeight := Image1.Height+10;
  Image1.Top := Form1.ClientRect.Top
   + (Form1.ClientHeight - Image1.Height) div 2;
  Form1.ClientWidth := Image1.Width+10;
  Image1.Left := Form1.ClientRect.Left
   + (Form1.ClientWidth - Image1.Width) div 2;
 end;

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

А вот это лишнее. Я про это , не спрашивал. Но все равно спасибо.

Оффлайн Acider

  • Пользователь
  • Сообщений: 237
    • Просмотр профиля
Re: Delphi (TImage)
« Ответ #6 : 24 Октябрь 2007, 11:16:02 »
GDI - графика в Delphi
 Previous  Top  Next 


     
 


 

 

Автор: Alistair Keys

 

Жаргон GDI.

 

GDI расшифровывается как Graphics Device Interface, и представляет собой интерфейс, который Windows использует для рисования 2D графики. Также это самый медленный способ отображения графики из существующих, однако самый простой для понимания основ. Итак, для начала, поговорим об основных понятиях и терминах в GDI.

 

Начнём с того, что GDI обычно не используют для создания крутых графических эффектов, для этого есть DirectX, OpenGL, или любые графические библиотеки (такие как: DelphiX, FastLib, DIBUltra, Graphics32...). Однако, для создание простых эффектов с минимальными усилиями GDI вполне сгодится.

 

С GDI тесно связана ещё одна аббревиатура - DC ("Device Context" - контекст устройства). Это то, на чём мы рисуем, и в Delphi контекст устройства представлен как TCanvas. Идея контекста устройства заключается в том, что это универсальное устройство вывода, поэтому можно использовать одинаковые функции как для экрана, так и для принтера.

 

Все графические функции в Delphi являются надстройками над стандартными GDI функциями Windows. Позже мы поговорим об этих функциях.

 

А теперь самое время приступить к рассмотрению того, как устроен GDI. Ниже, в таблице, представлены некоторые важные классы:

 

 

Pen Используется для рисования простых линий. Обычно применяется для функции LineTo или при рисовании рамки для определённой фигуры (например для функции Rectangle).

 

Brush Кисть используется для заполнения области определённым цветом. Применяется в функциях Rectangle, FillRect или FloodFill.

 

Font Используется для задания шрифта, которым будет нарисован текст. Можно указать имя шрифта, размер и т.д.

 

Region Позволяет задать регион (замкнутое пространство). Регионом может быть круг, квадрат или произвольная фигура. Позволяет так же делать дырки в фигурах.

 

Однако, пора переходить от слов к делу, а именно, начать рисовать линии и фигуры.

 

Рисование линий

 

Сперва необходимо чётко уяснить, что координата (0,0) это верхний левый угол экрана. То есть значения по оси y увеличиваются вниз экрана. Соответственно, координата (0, 50) означает, что мы просто отступили на 50 пикселей от верха экрана.

 

Самое главное, что надо знать при рисовании линий и фигур, это различие между пером (Pen) и кистью (Brush). Всё очень просто: перо (Pen) используется при рисовании линий или рамок, а кисть (Brush) для заполнения фигуры.

 

Ниже приведены две функции, которые используются для рисования линий и обе принадлежат TCanvas:

 

MoveTo Перемещает точку начала рисования линии в указанные координаты x и y Canvas.MoveTo(50, 100);

 

LineTo Рисует линию начиная с текущей позиции (см. MoveTo) до указанных координат x и y. Canvas.LineTo(50, 100);

 

Эффект перемещения точки начала рисования линии так же достигается при помощи установки своства PenPos в канвасе... например, "Canvas.PenPos.x := 20;", "Canvas.PenPos.y := 50", или "Canvas.PenPos := Point(20,50);".

 

По умолчанию, точка начала рисования установлена в (0,0), то есть, если сразу вызвать "Canvas.LineTo(100,100);" то будет нарисована линия из точки (0,0) в точку (100, 100). Точка начала рисования автоматически переместится в (100, 100), то есть, если выполнить команду "Canvas.LineTo(200, 100);", то следующая линия будет нарисована из точки (100, 100) в (200, 100). Поэтому, если мы хотим рисовать линии несоединённые друг с другом, то придётся воспользоваться методом MoveTo.

 

Линия, нарисованная при помощи LineTo использует текущее перо канваса (типа TPen). Основные свойства пера, это ширина - "Canvas.Pen.Width := 4;" (при помощи которого можно задавать различную ширину линий), и цвет "Canvas.Pen.Color := clLime;".

 

Взглянем на простой пример беспорядочного рисования разноцветных линий:

Code:
 
procedure TForm1.FormCreate(Sender: TObject);

begin

// инициализируем генератор

// случайных чисел

Randomize;

end;

 

const

NUM_LINES = 2000;

 

procedure TForm1.DrawLines;

var

i: Integer;

begin

for i := 0 to NUM_LINES - 1 do

begin

   Canvas.Pen.Color :=

     RGB(Random(256),

     Random(256),

     Random(256));

   Canvas.LineTo

     (Random(ClientWidth),

     Random(ClientHeight));

end;

end;
 

 

 

 

 

 

 

Процедура DrawLines вызывается из обработчика кнопки OnClick. Количество линий задаётся в константе NUM_LINES. Между прочим, функция RGB, составляет цвет каждой линии из трёх основных составляющих: красного, зелёного и синего (значения от 0 до 255) и возвращает нам цвет в виде TColor.

 

 

Рисование фигур

 

Для рисования фигур, в TCanvas предусмотрены следующие функции:

 

Ellipse Рисует элипс, вписанный в невидимый квадрат с координатами верхнего левого угла и правого нижнего. Если координаты х и y у углов будут совпадать, то получится круг. Canvas.Ellipse(0,0,50,50);

 

FillRect Заполняет прямоугольник цветом текущей кисти (brush), но никак не за пределами него. Canvas.FillRect( Bounds(0,0,100,100));

 

FloodFill Заполняет данную область цветом текущей кисти, до тех пор пока не будет достигнут край. Canvas.FloodFill(10, 10, clBlack, fsBorder);

 

Rectangle Рисует прямоугольник (или квадрат), заполненный цветом текущей кисти и обрамлённый цветом текущего пера Canvas.Rectangle( Bounds(20, 20, 50, 50));

 

RoundRect Тоже, что и Rectangle, но с загруглёнными углами. Canvas.RoundRect( 20, 20, 50, 50, 3, 3);

 

 

Ещё есть очень нужная функция TextOut, которая позволяет рисовать текст, используя шрифт, заданный в канвасе:

 

TextOut Рисует данную строку на канвасе начиная с координат (x,y) - фон текста заполняется текущим цветом кисти. Canvas.TextOut(10, 10, 'Some text');

 

Кстати, функция позволяет рисовать текст, не заполняя его фон. Если Вам необходимо изменить шрифт, используемый в TextOut, то необходимо изменить свойство Font канваса (это свойство имеет тип TFont) - например "Canvas.Font.Name := 'Verdana';", "Canvas.Font.Size := 24;" или "Canvas.Font.Color := clRed;".

 

Вкратце хотелось бы обратить Ваше внимание на довольно полезный класс TRect, который умеет хранить в себе значения лево, право, верха и низа (кстати, в Windows API это RECT). То ест, достаточно указать левую и верхнюю координату и ширину и высоту области, а TRect автоматически подставит в виде (лево, верх, лево + ширина, верх + высота). Ещё есть другая функция Rect(), которая делает тоже самое, но координаты в ней задаются напрямую как лево, право, верх и низ. Ну и по желанию, можно использовать API функцию SetRect.

 

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

Code:
 
const

NUM_SHAPES = 200;

 

procedure TForm1.DrawShapes;

var

i, ShapeLeft, ShapeTop: Integer;

begin

for i := 0 to NUM_SHAPES - 1 do

begin

   Canvas.Brush.Color :=

     RGB(Random(256),

     Random(256),

     Random(256));

   ShapeLeft := Random(ClientWidth);

   ShapeTop := Random(ClientHeight);

   // теперь, случайным образом, решаем что рисовать

   case Random(3) of

     0: Canvas.Rectangle(ShapeLeft,

         ShapeTop,

         ShapeLeft + Random(50),

         ShapeTop + Random(50));

     1: Canvas.Ellipse(ShapeLeft,

         ShapeTop,

         ShapeLeft + Random(50),

         ShapeTop + Random(50));

     2:

       begin

         Canvas.Font.Size := 10 + Random(7); // от 10 до 16

         Canvas.TextOut(ShapeLeft, ShapeTop, 'Some text');

       end;

   end;

end;

end;
 

 

 

Как Вы уже успели заметить, некоторые фигурки имеют цвет рамки, отличающийся от того цвета, которым заполнена фигура. Это как раз тот момент, о котором я упоминал выше. Кистью мы заполняем объекты, а пером обрамляем. Если цвет кисти (brush) меняется случайным образом, то цвет пера(pen) остаётся постоянным. Из-за этого и получается такая картина.

 

Перерисовка окна

 

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

 

Рисование, это то, что мы делали выше. То есть, рисовали любые линии и графические фигуры. Однако, рисунок сохранялся до тех пор, пока окно(форма) не было обновлено.

 

Перерисовка несколько отличается от понятия "рисование". Когда окну необходимо перерисоваться, то Windows посылает определённое сообщение. Это сообщение поступает в обработчик события "OnPaint". Любой код, который поместить в обработчик OnPaint будет вызван каждый раз, когда форме необходимо обновиться.

 

Для примера, поместите следующий код в проект:

Code:
 
procedure TForm1.DrawSomeText;

begin

Canvas.TextOut(10, 10, 'Some text');

end;
 

 

Если поместить на форму кнопку и вызывать DrawSomeText из обработчика кнопки OnClick, то проблема с исчезновением текста при перемещении формы останется. ОДНАКО, если вызвать DrawSomeText из обработчика формы OnPaint, то текст останется на своём месте окончательно.

 

Дескрипторы, или как пользоваться аналогичными API функциями

 

Итак, мы научились рисовать линии, различные фигуры, научились делать так, чтобы наше творение не стиралось при перемещении формы, и проделали мы всё это при помощи стандартных функций VCL (таких как Canvas.TextOut и т.д.). Однако, что делать, если Вы не хотите пользоваться графическими функциями VCL, которые всего навсего являются надстройками над аналогичными функциями из Windows API? Пожалуйста! Никто нам не запрещает пользоваться API функциями напрямую! Но постойте-ка, все они требуют какого-то HDC! Что такое HDC?

 

Почти всё в Windows использует "Дескриптор" (Handle). Дескриптор, это способ идентификации Вашего объекта в системе. У каждого окна есть свой дескриптор, у каждой кнопки тоже есть свой дескриптор и т.д. Именно поэтому все наши объекты имеют дескриптор в качестве свойства - например, "MyForm.Canvas.Handle".

 

Тип HDC это Дескриптор(Handle) Контекста Устройства (Device Context). Я уже говорил в самом начале, что TCanvas включает в себя большинство функций DC. Поэтому, мы спокойно можем подставлять свойство канваса Handle везде, где нам это потребуется.

 

Ради интереса можно взглянуть на таблицу, в которой представлены примеры вызовов некоторых функций из VCL и их аналогов из Windows API.

 

Canvas.TextOut(x,y,myString);                TextOut(Canvas.Handle, x, y, PChar(myString), Length(String));

 

Canvas.FloodFill(X, Y, Color,fsBorder);        ExtFloodFill(Canvas.Handle, x, y, YourColour, FLOODFILLBORDER);

 

Canvas.LineTo(x,y);                                LineTo(Canvas.Handle, x, y);

 

Canvas.MoveTo(x,y);                                MoveToEx(Canvas.Handle, x, y, nil);

 

Так же можно использовать разные дескрипторы, чтобы рисовать в разных местах. Например, можно использовать "SomeBmp.Canvas.Handle" для рисования на картинке (битмапе), либо "Form1.Canvas.Handle", чтобы рисовать на форме.

 

В API версии функции TextOut необходимо передавать строку завершённую нулём. Это значит, что вместо того, чтобы передать строку в функцию напрямую, необходимо передать её как PChar. Так же не забывайте передавать в функцию длину строки. Для этого можно воспользоваться функцией Length.

 

Ну что, Вам уже захотелось поместить на форму какую-нибудь красивую картинку ?

 

Что такое Битмапы (Bitmaps)?

 

Рисование линий, это, конечно, хорошо, но рано или поздно Вам понадобится нарисовать более реалистичную картнику в своём приложении. Поэтому совершенно необходимо научиться работать с растровыми изображениями, или как их называют в среде программистов - битмапами.

 

Битмап, это графический объект, который содержит заголовок, необходимую информацию о картинке (такую как высота, ширина, цвета и т.д.) и, собственно, само изображение (большой массив, содержащий цвет каждой точки). В Delphi для этой цели уже предусмотрен класс TBitmap.

 

Битмапы можно рисовать не только на форме, но и по всему экрану. Может это и может показаться немного странным, но иногда это бывает полезно, особенно при создании скринсейвера. Однако, сначала нам необходимо разобраться с тем, как работать с битмапами. Вот небольшой пример:

Code:
 
procedure Form1.DrawBitmap(const Filename: string; const x, y: Integer);

var

Bmp: TBitmap;

begin

// Сперва убедимся, что файл существует!

if not FileExists(Filename) then

begin

   ShowMessage('The bitmap ' + Filename + ' was not found!');

   Exit;

end;

 

Bmp := TBitmap.Create;

try

   Bmp.LoadFromFile(Filename);

   Canvas.Draw(x, y, Bmp);

finally

   Bmp.Free;

end;

end;
 

 

 

 

 

 

 

Эта функция пытается загрузить и показать картинку, (с именем Filename, например 'myBitmap.bmp') начиная с точки (x,y).

 

Сразу скажу, что эта функция довольно неэффективна. Она создаёт и уничтожает битмап каждый раз когда вызывается, а так же каждый раз проверяет существование файла. Лучше объявлять объект TBitmap как часть формы, создавать и загружать картинку в FormCreate, а освобождать её в FormDestroy.

 

Функции рисования в GDI

 

TCanvas имеет несколько полезных функций, которые работают с типом TGraphic. Тип TGraphic является базовым классом для графических объектов в Delphi, таких как: битмапы (TBitmap), иконки (TIcon), метафайлы (TMetafile) и JPEG-и (TJPEGImage). Все они используют одни и те же функции, которые приведены в таблице:

 

Все эти функции являются методами TCanvas.

 

Draw Рисует TGraphic на канвасе так как он есть, не растягивая. Canvas.Draw(5,10,MyGraphic);

 

StrechDraw Рисует TGraphic на канвасе, подгоняя (растягивая) его под заданную область. Canvas.StretchDraw( Bounds(0,0,32,32), MyGraphic);

 

CopyRect Копирует часть TCanvas-а в другой, при необходимости растягивая его. Canvas.CopyRect( Bounds(0,0,32,32), MyBmp.Canvas, Bounds(0, 0, 640, 480));

 

TCanvas.Draw является обёрткой для API функции BitBlt:

 

function BitBlt(

hdcDest: HDC; // дескриптор конечного контекста устройства

nXDest, // коорд. x верхнего левого угла конечного прямоугольника

nYDest, // коорд. y верхнего левого угла конечного прямоугольника

nWidth, // ширина конечного прямоугольника

nHeight: Integer; // высота конечного прямоугольника

hdcSrc: HDC; // дескриптор исходного контекста устройства

nXSrc, // коорд. x верхнего левого угла исходного прямоугольника

nYSrc: Integer; // коорд. y верхнего левого угла исходного прямоугольника

dwRop: DWORD // код растровой операции

): Boolean;

 :) Даааааа. Это яи так знаю, и многое другое. Просто такую мелоч забыл. И мне уже подсказали.
А в кодах и в работе с канвой я шарю, хотя и призабыл кое что. Спасибо.

Оффлайн Zephyr

  • Пользователь
  • Сообщений: 544
  • Пол: Мужской
  • coder
    • Просмотр профиля
Re: Delphi (TImage)
« Ответ #7 : 24 Октябрь 2007, 11:48:18 »
На VCL игры не пишут :)
Есть GDI (не VCL), OpenGL, DirectX, SDL...
Есть готовые движки на этих API...
Попробуй неплохой движок от моего приятеля SVD_Val на OpenGL:
http://www.svsd.mirgames.ru/