Практическое занятие № 8
Тема: "Работа с графикой"
Цель работы: получить практические навыки по работе с компонентами отображения графических данных
Ход работы
Создайте форму для просмотра графических файлов вида:

Указания: для формы задайте свойства: Caption=Выбор изображения.
Установка компонентов для создания Проводника Windows на форме
Как видно на рисунке, просмотр графических файлов будем выполнять с помощью специальных компонентов, напоминающих Проводник Windows. Данные компоненты имеются в Delphi, но, по умолчанию, не установлены. Для их установки необходимо выполнить следующие действия:
- распакуйте архив с файлами компонентов;
- в среде Delphi из распакованной папки откройте файл vclshlctrls.dpk. В результате на панели Project manager в правом верхнем углу экрана отобразится проект vclshlctrls70.bpl. Щелкните на нем правой кнопкой мыши и выберите команду Compile;
- в среде Delphi из распакованной папки откройте файл dclshlctrls.dpk. В результате на панели Project manager в правом верхнем углу экрана отобразится проект dclshlctrls70.bpl. Щелкните на нем правой кнопкой мыши и выберите команду Compile. Еще раз щелкните на нем правой кнопкой мыши и выберите команду Install;
- в результате в группе Samples появятся два новых компонента: TShellTreeView и TShellListView. Вы можете использовать их в будущем для создания своих проектов.
Нанесите на форму компонент ShellTreeView для отображения дерева папок.
Нанесите на форму компонент ShellListView для отображения списка элементов в выбранной папке. Для связывания компонента с деревом папок в его свойстве ShellTreeView укажите ссылку на компонент ShellTreeView1.
Для отображения в списке только графических файлов для компонента ShellListView в событии OnAddFolder введите код:
procedure TForm1.ShellListView1AddFolder(Sender: TObject; AFolder: TShellFolder; var CanAdd: Boolean);
//переменная - признак добавления файла в список элеметов папки (1 - добавить, 0 - нет)
var yes:integer;
//переменная для выделения расширения из файла
ext:string;
begin
//предполагаем, что текущий элемент не подходит для добавления
yes:=0;
//если очередной элемент - папка
if AFolder.IsFolder then
//то включаем признак добавления
yes:=1
else
//иначе, если очередной элемент не папка, т.е. файл
begin
//извлекаем расширение из имени файла
//преобразуем расширение в строчные буквы функцией LowerCase()
//на случай,если расширения будут записаны в разном регистре
ext:=LowerCase(ExtractFileExt(AFolder.PathName));
//если расширение - это расширение графического файла
if (ext='.jpg') or (ext='.bmp') or (ext='.gif') or (ext='.png') then
//то включаем признак добавления
yes:=1;
end;
//если признак добавления не включен
if yes=0 then
//отменяем добавление очередного элемента
CanAdd:=false;
end;
Под деревом папок нужно отображать содержимое выбранного графического файла.
Указания: нанесите на форму компонент Image (Additional) и задайте свойства: Stretch = true - масштабирование рисунка, Proportional = true - масштабирование с сохранением пропорций сторон, Center = true - выравнивать изображение по центру компонента.
Для работы с 4 основными графическими форматами необходимо учитывать следующее:
- формат bmp поддерживается автоматически;
- формат jpg поддерживается, но для работы с ним нужно подключить модуль JPEG;
- формат gif не поддерживается. Для работы с ним скачайте файл GifImage.zip, поместите содержимое архива в папку с вашим проектом и подключите модуль GifImage;
- формат png не поддерживается. Для работы с ним скачайте файл PNGImage.zip, поместите содержимое архива в папку с вашим проектом и подключите модуль PngImage.
Отображение файла в компоненте Image должно выполняться после щелчка на файле в списке. Для этого в событии OnClick компонента ShellListView введите код:
procedure TForm1.ShellListView1Click(Sender: TObject);
begin
//если в списке выбран не пустой элемент (щелкнули не на пустом фоне окна)
if (ShellListView1.Selected<>nil) and
//и выбранный элемент в списке не папка
not (ShellListView1.SelectedFolder.IsFolder) then
//в компонент Image1 загружаем выбранный файл
Image1.Picture.LoadFromFile(ShellListView1.SelectedFolder.PathName)
end;
По двойному щелчку на компоненте Image открывается новое окно с увеличенным изображением.
Указания: добавьте в проект новую форму. Для формы задайте свойства: Caption = Просмотр изображения, Position = poDesktopCenter. В свойствах проекта перенесите созданную форму в список Available Forms.
Нанесите на форму компонент Image и задайте для него свойства: Align = alClient - компонент заполняет всю форму, Stretch = true - масштабирование рисунка, Proportional = true - масштабирование с сохранением пропорций сторон, Center = true - выравнивать изображение по центру компонента.
Перейдите на главную форму и для компонента Image в событии OnDblClick введите код:
procedure TForm1.Image1DblClick(Sender: TObject);
begin
//если изображения в компоненте Image нет, то конец работы процедуры
if Image1.Picture.Graphic=nil then
exit;
//создаем в памяти экземпляр формы
Form2:=TForm2.Create(nil);
//отображаем форму как модальную
Form2.ShowModal;
end;
При отображении второй формы на ней в компоненте Image должно отображаться изображение из Image на главной форме. Для этого в событии OnShow второй формы введите код:
procedure TForm2.FormShow(Sender: TObject);
begin
//загружаем в компонент Image содержимое компонента Image главной формы
Image1.Picture.Assign(Form1.Image1.Picture);
end;
Для удаления созданной формы из памяти перейдите на вторую форму и в событии OnClick введите код:
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:=caFree;
end;
Для выполнения работы с изображением на главной форме для компонента Image создадим контекстное меню.

Указания: нанесите на форму компонент PopupMenu. Двойным щелчком на нем откройте редактор меню и введите команды: Сохранить..., Разделитель, Вырезать, Копировать, Вставить, Разделитель, Изменить размер...
Для присваивания созданного меню для компонента Image в свойстве PopupMenu укажите созданное меню.
Команды контекстного меню нужно блокировать и разблокировать в зависимости от состояния изображения и буфера обмена.
В событии OnPopup компонента PopupMenu введите код:
procedure TForm1.PopupMenu1Popup(Sender: TObject);
begin
//если изображения в Image нет
if Image1.Picture.Graphic=nil then
begin
//блокируем команды Сохранить..., Вырезать, Копировать, Изменить размер...
n1.Enabled:=false;
n3.Enabled:=false;
n4.Enabled:=false;
n7.Enabled:=false;
end
//иначе, если изображения в Image есть
else
begin
//разблокируем команды Сохранить..., Вырезать, Копировать, Изменить размер...
n1.Enabled:=true;
n3.Enabled:=true;
n4.Enabled:=true;
n7.Enabled:=true;
end;
//если в буфере обмена графическая информация
if not Clipboard.HasFormat(CF_PICTURE) then
//команда Вставить разблокируется
n5.Enabled:=false
//иначе, если в буфере обмена не графическая информация
else
//команда Вставить блокируется
n5.Enabled:=true;
end;
Команда Сохранить... должна выдавать диалог и предлагать пользователю выбрать один из 4 типов файлов.
Указания: нанесите на форму компонент SavePictureDialog. Для компонента задайте свойства: Filter = Bitmaps (*.bmp)|*.bmp|JPEG Image (*.jpg)|*.jpg|GIF Image (*.gif)|*.gif|PNG Image (*.png)|*.png - список форматов для сохранения, DefaultExt = bmp - тип файла по умолчанию.
При изменении типа файла в диалоге нужно менять расширение по умолчанию. Для этого в событии OnTypeChange диалога введите код:
procedure TForm1.SavePictureDialog1TypeChange(Sender: TObject);
begin
//номер типа файла находится в свойстве FilterIndex (нумерация с 1)
//проверяем какой тип файла был выбран и задаем соотвествующее расширение
case SavePictureDialog1.FilterIndex of
1: SavePictureDialog1.DefaultExt:='bmp';
2: SavePictureDialog1.DefaultExt:='jpg';
3: SavePictureDialog1.DefaultExt:='gif';
4: SavePictureDialog1.DefaultExt:='png';
end;
end;
Напишем код для команды Сохранить... Двойным щелчком откройте меню PopupMenu и двойным щелчком откройте код команды Сохранить... Введите код:
procedure TForm1.N1Click(Sender: TObject);
//переменные для работы с файлами в разных форматах
var bmp:TBitmap;
jpg:TJpegImage;
gif:TGifImage;
png:TPngObject;
begin
//очищаем предыдущее имя файла
SavePictureDialog1.FileName:='';
//если файл в диалоге сохранения не указан, конец работы процедуры
if not SavePictureDialog1.Execute then
Exit;
//в зависимости от выбранного типа файла (свойство FilterIndex)
//сохраняем содержимое Image в соотвествующий формат
case SavePictureDialog1.FilterIndex of
//если выбран первый формат (bmp)
1: begin
//создаем экземпляр класса для работы с форматом bmp
bmp:=TBitmap.Create;
//загружаем в класс содержимое компонента Image (конвертируем изображение)
bmp.Assign(Image1.Picture.Graphic);
//сохраняем полученное изображение в файл
bmp.SaveToFile(SavePictureDialog1.FileName);
//удаляем экземпляр класса из памяти
bmp.Free;
end;
//аналогично формат jpg
2: begin
jpg:=TJpegImage.Create;
jpg.Assign(Image1.Picture.Graphic);
jpg.SaveToFile(SavePictureDialog1.FileName);
jpg.Free;
end;
//аналогично формат gif
3: begin
gif:=TGifImage.Create;
gif.Assign(Image1.Picture.Graphic);
gif.SaveToFile(SavePictureDialog1.FileName);
gif.Free;
end;
//формат png можно получить только из bmp формата
4: begin
//создаем экземпляр класса для работы с форматом bmp
bmp:=TBitmap.Create;
//загружаем в класс содержимое компонента Image (конвертируем изображение)
bmp.Assign(Image1.Picture.Graphic);
//создаем экземпляр класса для работы с форматом png
png:=TPngObject.Create;
//загружаем в png изображение bmp (происходит конвертирование)
png.Assign(bmp);
//сохраняем полученное изображение
png.SaveToFile(SavePictureDialog1.FileName);
//удаляем созданные экземпляры классов
png.Free; bmp.Free;
end;
end;
end;
Реализуйте возможность работы с графикой через буфер обмена.
Указания: для работы с буфером обмена подключите модуль ClipBrd..
Двойным щелчком откройте меню PopupMenu и двойным щелчком откройте процедуру команды Вырезать. Введите код:
procedure TForm1.N3Click(Sender: TObject);
begin
//копируем содержимое Image в буфер обмена
Clipboard.Assign(Image1.Picture);
//очищаем содержимое Image
Image1.Picture:=nil;
end;
Для команды Копировать напишите код:
procedure TForm1.N4Click(Sender: TObject);
begin
//копируем содержимое Image в буфер обмена
Clipboard.Assign(Image1.Picture);
end;
Для команды Вставить напишите код:
procedure TForm1.N5Click(Sender: TObject);
begin
//в компонент Image помещается содержимое буфера обмена
Image1.Picture.Assign(Clipboard);
end;
Для команды Изменить размер... организуйте вывод новой формы с возможностью задания нового размера изображения.
Указания: создайте новую форму и задайте для нее свойства: Caption = Новый размер, BorderStyle = bsDialog, Position = poDesktopCenter. В окне свойств проекта перенесите форму в список Available Forms. Двойным щелчком откройте меню PopupMenu и двойным щелчком откройте процедуру команды Изменить размер... Введите код:
procedure TForm1.N7Click(Sender: TObject);
begin
//создаем экземпляр формы в памяти
form3:=TForm3.Create(nil);
//отображаем созданную форму как модальную
Form3.ShowModal;
end;
При закрытии формы она должна удаляться из памяти. Перейдите на созданную форму и в событии OnClose ведите код:
procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:=caFree;
end;
Форму задания размера файла оформите как показано на рисунке. При открытии формы поля Ширина и Высота должны автоматически заполняться реальными размерами изображения, отображаемого в компоненте Image главной формы. При вводе ширины или высоты значение в соседнем поле должно автоматически изменяться с соблюдением пропорций рисунка.

Указания: нанесите на форму две надписи, два текстовых поля и две кнопки. Для перовой кнопки задайте свойство Default = true, для второй - Cancel = true.
Для сохранение пропорций сторон рисунка опишем глобальную переменную для хранения коэффициента соотношения сторон:
prop:real;
В событии OnCreate формы заполним поля реальными размерами изображения и вычислим коэффициент пропорции.
procedure TForm3.FormCreate(Sender: TObject);
begin
//первое поле - ширина изображения из Image на главной форме
Edit1.Text:=IntToStr(Form1.Image1.Picture.Width);
//второе поле - высота изображения из Image на главной форме
Edit2.Text:=IntToStr(Form1.Image1.Picture.Height);
//коэффициент пропорции = ширина/высота
prop:=Form1.Image1.Picture.Width/Form1.Image1.Picture.Height;
end;
При изменении значения ширины высота должна автоматически пересчитываться с учетом коэффициента. В событии OnKeyDown поля Edit1 введите код:
procedure TForm3.Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
Edit2.Text:=FloatToStr(Round(StrToInt(Edit1.Text)/prop));
end;
При изменении значения высоты ширина должна автоматически пересчитываться с учетом коэффициента. В событии OnKeyDown поля Edit2 введите код:
procedure TForm3.Edit2KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
Edit1.Text:=FloatToStr(Int(StrToInt(Edit2.Text)*prop));
end;
Кнопка Отмена закрывает окно.
procedure TForm3.Button2Click(Sender: TObject);
begin
Close;
end;
Кнопка ОК изменяет размер рисунка и помещает его в компонент Image на главной форме.
procedure TForm3.Button1Click(Sender: TObject);
//переменные для работы с изображением
//bmp - исходное изображение
//tempbmp - полученное изображение после изменения размера
var
bmp,tempbmp:TBitMap;
begin
//если один из размеров изображения не указан
if (Edit1.Text='') or (Edit2.Text='') then
begin
//выдаем сообщение об ошибке
Application.MessageBox('Выполнение операции невозможно. Укажите правильно размер изображения',
'Ошибка',MB_OK+MB_IconError);
//завершаем работу процедуры
Exit;
end;
//создаем экземпляр класса для исходного изображения
bmp:=TBitMap.Create;
//помещаем в класс изображение из компонента Image на главной форме
bmp.Assign(Form1.Image1.Picture.Graphic);
//создаем экземпляр класса для нового изображения
tempbmp:=TBitMap.Create;
//задаем новому изображению ширину и высоту из полей на форме
tempbmp.Width:=StrToInt(Edit1.Text);
tempbmp.Height:=StrToInt(Edit2.Text);
//задаем параметры нового изображения
tempbmp.PixelFormat:=pf24bit;
//задаем для нового изображения гладкое масштабирование
SetStretchBltMode(tempbmp.Canvas.Handle,4);
//копируем исходное изображение в новое (происходит увеличение)
StretchBlt(tempbmp.Canvas.Handle,0,0,tempbmp.Width,tempbmp.Height,
bmp.Canvas.Handle, 0,0,bmp.Width,bmp.Height,SRCCOPY);
//в компонент Image на главной форме помещаем полученное изображение
Form1.Image1.Picture.Assign(tempbmp);
//удаляем из памяти экземпляры класса
tempbmp.Free;
bmp.Free;
//выдаем сообщение об успешном завершении операции
Application.MessageBox('Обработка завершена. Можете сохранить изображение в файл',
'Операция завершена',MB_OK+MB_IconInformation);
//закрываем форму
Close;
end;