Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа №21.pdf
Скачиваний:
17
Добавлен:
16.03.2015
Размер:
1 Mб
Скачать

Лабораторные работы по информатике для специальности «Моделирование и исследование операций в организационно-технических системах»

if gdSelected in State then Brush.Color:=clBlue;

//рисуем фон ячейки

FillRect(Rect); //рисуем текст

TextRect(Rect, Rect.Left+2, Rect.Top+2, sgrTable.Cells[ACol, ARow]);

end;{with} end;

Вид окна программы приведен на рисунке 11.

Рисунок 11 – Вид таблицы после изменения процедуры прорисовки

Запустите программу, проверьте ее функционирование.

TDrawGrid

Компонент TDrawGrid предоставляет программисту мощные возможности

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

Чтобы таблица была работоспособной, в ней как минимум следует определить обработчик события OnDrawCell, которое возникает при необходимости прорисовать ту или иную ячейку. Для прорисовки используется табличное свойство Canvas.

Компонент TDrawGrid является непосредственным родителем строковой таблицы TStringGrid, поэтому передает ей все свои свойства, методы и события за исключением специфичных для строк свойств Cells, Cols, Objects и Rows.

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

Шаг 1. Создайте новый проект. На форму frmDGrid поместите два компонента TPanel (pnCommand, pnGrid) и один компонент TSplitter (VSplitter). Установите значение

Лабораторные работы по информатике для специальности «Моделирование и исследование операций в организационно-технических системах»

свойства Align компонента pnGrid равным alLeft, а значение этого же свойства компонента pnCommand равным alClient. Компонент VSplitter должен находится между двумя панелями, разделяя их. Установите значение свойства Caption формы равным

«Компонент TDrawGrid» (рисунок 12).

Рисунок 12 – Вид формы после добавления панелей.

Шаг 2. Поместите на панель pnGrid компонент TDrawGrid (DrawGrid). Установите значение свойства Align компонента DrawGrid равным alClient. Установите значения свойств ColCount и RowCount равным 1, а значения свойств FixedRows и FixedCols

равным нулю. Установите значение свойства Scrollbars равным ssVertical. Поместите на панель pnCommand кнопку btnExit (рисунок 13). Настройте свойство Anchors кнопки так, чтобы при изменении размеров она прижималась к нижнему правому углу панели. Создайте обработчик события для кнопки, закрывающий форму.

Рисунок 13 – Вид формы после добавления компонента TDrawGrid и компонента TButton.

При старте программы необходимо сканировать заданный каталог программы, выбирая из него нужные файлы. Затем для каждого файла создать уменьшенную копию изображения (эскиз) и поместить ее в список изображений. Для хранения эскизов изображений удобно использовать класс TStringList (см. лабораторную работу № 11).

Лабораторные работы по информатике для специальности «Моделирование и исследование операций в организационно-технических системах»

Шаг 3. Поместите в раздел public формы следующую строку.

SketchList:TStringList;

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

procedure TfrmDGrid.FormCreate(Sender: TObject); begin

//создаем список

SketchList:=TStringList.Create;

end;

После окончания работы со списком его необходимо уничтожить. Создайте обработчик события OnDestroy для формы и поместите в него нижеприведенный текст.

procedure TfrmDGrid.FormDestroy(Sender: TObject); var i:Integer;

begin

//удаляем список

SheetList.Free;

end;

Для перебора всех файлов из текущего каталога будем использовать две стандартные функции FindFirst и FindNext, которые позволяют получить список всех файлов находящихся в каталоге, по заданному критерию отбора. Рассмотрим их более подробно. Функция FindFirst имеет следующий синтаксис

function FindFirst (const Path: string; Attr: Integer; var F: TSearchRec): Integer;

где Path – каталог, в котором осуществляется поиск файлов, а также маска по которой будут отбираться файлы (например “C:\*.*” – выбрать все файлы из корневого каталога диска С);

Attr – атрибуты файлов которые будут отбираться при поиске (например можно указать скрытые файлы или файлы только для чтения);

F – запись содержащая информацию о найденном файле. Ниже приведено описание типа TSearchRec.

type

TSearchRec = record

Time: Integer; // время последней модификации файла Size: Integer; // размер файла в байтах

Attr: Integer; // атрибуты файла

Name: TFileName;// имя файла с расширением

ExcludeAttr: Integer;

FindHandle: THandle;

FindData: TWin32FindData; // дополнительная информация о файле end;

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

Обратите внимание, что во время осуществления поиска функция FindFirst занимает память, поэтому после окончания поиска ее следует освободить с помощью процедуры

FindClose.

procedure FindClose(var F: TSearchRec);

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

Лабораторные работы по информатике для специальности «Моделирование и исследование операций в организационно-технических системах»

function FindNext(var F: TSearchRec): Integer;

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

Таким образом, алгоритм выбора всех файлов из каталога состоит в следующем. Вызывается функция FindFirst, с указанием каталога и параметров поиска. Если результат работы функции равен нулю, то в цикле вызываем функцию FindNext до тех пор, пока ее значение не станет отличным от нуля. После каждого вызова функции FindNext извлекаем из параметра F имя файла и его параметры. Далее вызываем процедуру FindClose для освобождения ресурсов занятых функцией FindFirst.

Шаг 4. Создайте в разделе public формы следующий метод.

procedure ScanDir;

Поместите в него ниже приведенный код

procedure TfrmDGrid.ScanDir; var Search:TSearchRec;

Path :string; // каталог для сканирования begin

//вычисляем путь до папки с файлами (каталог программы) Path:=ExtractFilePath(Application.ExeName);

//сканируем каталог

try

if FindFirst(Path+'*.*', 0, Search)=0 then repeat

// если расширение файла jpg или bmp

if (ExtractFileExt(Search.Name)='.jpg')or (ExtractFileExt(Search.Name)='.bmp') then

begin

// добавляем файл в список

SketchList.AddObject(Path+Search.Name, nil); end;{if}

until FindNext(Search)<>0; finally

FindClose(Search);// закрываем поиск end;{finally}

end;{ScanDir}

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

procedure TfrmDGrid.FormCreate(Sender: TObject); begin

//создаем список

SketchList:=TStringList.Create; //сканирование каталога программы

ScanDir;

end;

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

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

Лабораторные работы по информатике для специальности «Моделирование и исследование операций в организационно-технических системах»

CellWidth

 

BorderSize

 

CellWidth-2·BorderSize

CellHeight

Текст

 

Поле эскиза

 

Рисунок 14 – Схема ячейки таблицы

Шаг 5. Добавьте в секцию public формы следующие поля

CellWidth:Integer;

//ширина

ячейки

CellHeight:Integer;

//высота

ячейки

BorderSize:Integer;

//отступ

от

края ячейки

BorderColor:TColor;

//цвет фона

бордюра

SelectBrdColor:TColor;//цвет фона

бордюра (выделенного)

SketchBkColor:TColor;

//цвет фона зоны эскиза

SketchTextColor:TColor; //цвет

текста

Создайте в секции public формы метод

procedure UpdateCellsParam; //устанавливает размер ячеек

Поместите в него следующий код

DrawGrid.DefaultColWidth:=CellWidth;

DrawGrid.DefaultRowHeight:=CellHeight;

Измените, обработчик события OnCreate формы как показано ниже

procedure TfrmDGrid.FormCreate(Sender: TObject); begin

//параметры ячейки

CellWidth:=64;

CellHeight:=80;

BorderSize:=5;

BorderColor:=clYellow;

SketchBkColor:=clGreen;

SketchTextColor:=clBlack;

SelectBrdColor:=clBlue; //устанавливаем размеры ячеек

UpdateCellsParam; //создаем список

SketchList:=TStringList.Create;

Лабораторные работы по информатике для специальности «Моделирование и исследование операций в организационно-технических системах»

procedure TfrmDGrid.FormCreate(Sender: TObject); begin

//параметры ячейки

CellWidth:=64;

CellHeight:=80;

BorderSize:=5;

BorderColor:=clYellow;

SketchBkColor:=clGreen;

SketchTextColor:=clBlack;

SelectBrdColor:=clBlue; //устанавливаем размеры ячеек

UpdateCellsParam; //создаем список

SketchList:=TStringList.Create; //сканирование каталога программы

ScanDir;

end;

Создайте обработчик события OnResize для компонента pnGrid (обработчика этого события у компонента TStringGrid нет). В этом обработчике рассчитывается количество столбцов таблицы, которое может быть отображено без ее прокрутки. Затем рассчитывается количество строк таблицы необходимое для того, чтобы разместить все эскизы из списка. Текст этого обработчика приведен ниже.

procedure TfrmDGrid.pnGridResize(Sender: TObject); begin

//вычисляем число строк и число столбцов таблицы

DrawGrid.ColCount:=DrawGrid.Width div CellWidth; DrawGrid.RowCount:=SketchList.Count div DrawGrid.ColCount + 1; //перерисовать таблицу

DrawGrid.Repaint;

end;

Теперь рассмотрим обработчик события OnDrawCell, который выполняет прорисовку ячеек таблицы. Текст обработчика приведен ниже. Обратите внимание, что он пока не содержит кода прорисовки собственно эскиза изображения. Текст обработчика достаточно

ColCount

ACol

ARow

0

1

2

3

4

5

6

7

Порядковый номер элемента списка, соответствующего ячейке

Рисунок 15 – К вычислению индекса изображения в списке по его

тривиален и не нуждается в дополнительных пояснениях. Пояснение алгоритма пересчета координат ячейки в номер элемента списка приведено на рисунке 15

procedure TfrmDGrid.DrawGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);

var Index:Integer;

Лабораторные работы по информатике для специальности «Моделирование и исследование операций в организационно-технических системах»

procedure TfrmDGrid.DrawGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);

var Index:Integer; CaptionRect:TRect; ImgTitle:string;

begin

// если список не пуст

if SketchList.Count<>0 then begin

//вычисляем индекс изображения в списке

Index:=ARow*DrawGrid.ColCount+ACol;

//если ячейка не пустая

if Index<SketchList.Count then begin //рисуем ячейку

with DrawGrid.Canvas do begin

//рисуем бордюр

Pen.Color:=SketchTextColor;

//если ячейка выделена, то цвет фона SelectBrdColor

if gdSelected in State then Brush.Color:=SelectBrdColor else Brush.Color:=BorderColor; //иначе BorderColor Rectangle(Rect);

//зона эскиза изображения

Brush.Color:=SketchBkColor;

Rectangle(Rect.Left+BorderSize,

Rect.Top+BorderSize, Rect.Right-BorderSize,

Rect.Top+(Rect.Right - Rect.Left)-BorderSize);

//зона текста //вычисляем размер области для вывода текста

CaptionRect.Left:=Rect.Left; CaptionRect.Top:= Rect.Bottom - 15; CaptionRect.Right:=Rect.Right; CaptionRect.Bottom:=Rect.Bottom; //устанавливаем цвет для вывода текста

Brush.Color:=BorderColor;

Font.Color:=SketchTextColor;

Rectangle(CaptionRect);

//вывод подписи для картинки (по центру) ImgTitle:= ChangeFileExt(ExtractFileName(

SketchList.Strings[Index]), ''); DrawGrid.Canvas.TextRect(CaptionRect,

CaptionRect.Left+(CellWidth-TextWidth(ImgTitle)) div 2, CaptionRect.Top, ImgTitle);

end;{with}

end;{if Index<ImgList.Count} end;{if ImgList.Count<>0}

end;{DrawGridDrawCell}

Поместите в каталог с программой несколько изображений в формате bmp или jpg и запустите программу. Примерный вид окна программы, после создания выше приведенных обработчиков событий, приведен на рисунке 16.

Лабораторные работы по информатике для специальности «Моделирование и исследование операций в организационно-технических системах»

Рисунок 16 – Вид окна программы после добавления обработчика события OnDrawCell

Теперь перейдем к формированию и загрузке эскизов в список.

Шаг 6. Создайте еще один метод в секции public формы.

function CreateSketchImage(AFileName:string):TBitmap;

Эта функция служит для создания уменьшенной копии изображения (эскиза) находящегося в файле AFileName. В качестве результата работы функция возвращает созданный эскиз, если эскиз не удалось создать, то возвращается пустой указатель (nil). Текст метода приведен ниже

function TfrmDGrid.CreateSketchImage(AFileName:string): TBitmap; var Picture:TPicture;

bmp:TBitmap; //объект для сохранения картинок SkRect:TRect; //координаты для миниатюры mas:real;

begin try try

//загружаем изображение

Picture:=TPicture.Create;

Picture.LoadFromFile(AFileName);

//подготовка изображения для показа его в таблице bmp:=TBitmap.Create; //создаем объект растр

//вычисление масштаба

if Picture.Width>Picture.Height then mas:=Picture.Width/(CellWidth-2*BorderSize-2)

else mas:=Picture.Height/(CellWidth-2*BorderSize-2);

//устанавливаем размер bmp.Width:=Trunc(Picture.Width/mas); bmp.Height:=Trunc(Picture.Height/mas);

//создаем уменьшенную копию изображения

SkRect.Left:=0;

SkRect.Top:=0;

SkRect.Right:=bmp.Width;

SkRect.Bottom:=bmp.Height; bmp.Canvas.StretchDraw(SkRect, Picture.Graphic);

Лабораторные работы по информатике для специальности «Моделирование и исследование операций в организационно-технических системах»

result:=bmp; except

on EInvalidGraphic do begin

MessageBox(Handle, 'Неверный формат изображения!', 'Ошибка', MB_OK or MB_ICONWARNING);

result:=nil; end;{EInvalidGraphic}

else result:=nil;

end;{except} finally

Picture.Free; end;{finally}

end;{CreateSketchImage}

Код метода тривиален, поясним лишь алгоритм масштабирования исходного изображения в эскиз. Сначала определяется, какой из размеров изображения больше ширина или высота. Затем вычисляется коэффициент масштаба относительно максимального размера изображения из условия, что он должен укладываться в размер зоны эскиза (CellWidth-2*BorderSize-2), напомню, что зона эскиза имеет форму квадрата. Затем оба размера изображения умножаются на масштабный коэффициент. Таким образом, определяются размеры уменьшенного изображения. На рисунке 17.а приведен пример масштабирования изображения вытянутого вдоль ширины, а на рисунке 17.б вытянутого вдоль высоты.

а) Изображение вытянуто вдоль ширины

б) Изображение вытянуто вдоль высоты

Рисунок 17 – К алгоритму масштабирования изображений

Измените метод ScanDir как показано ниже

procedure TfrmDGrid.ScanDir; var Search:TSearchRec;

Path :string; // каталог для сканирования

Sketch:TBitmap; begin

//вычисляем путь до папки с файлами (каталог программы) Path:=ExtractFilePath(Application.ExeName);

//сканируем каталог

try

if FindFirst(Path+'*.*', 0, Search)=0 then repeat

Лабораторные работы по информатике для специальности «Моделирование и исследование операций в организационно-технических системах»

// если расширение файла jpg или bmp

if (ExtractFileExt(Search.Name)='.jpg')or (ExtractFileExt(Search.Name)='.bmp') then

begin Sketch:=CreateSketchImage(Path+Search.Name); // если удалось создать эскиз

if Sketch<>nil then // добавляем файл в список

SketchList.AddObject(Path+Search.Name, Sketch); end;{if}

until FindNext(Search)<>0; finally

FindClose(Search); // закрываем поиск end;{finally}

end;{ScanDir}

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

procedure TfrmDGrid.FormDestroy(Sender: TObject); var i:Integer;

begin

//удаляем эскизы (TBitmap) из списка for i:=0 to SketchList.Count-1 do

SketchList.Objects[i].Free; //удаляем список

SketchList.Free;

end;

Добавьте к списку модулей модуль Jpeg для работы с файлами jpeg. Откомпилируйте и запустите программу, убедитесь, что она работает без ошибок. Для отображения эскизов в таблице необходимо лишь модифицировать обработчик OnDrawCell компонента

DrawGrid.

Шаг 7. Внесите следующие изменения в обработчик события OnDrawCell компонента

DrawGrid.

procedure TfrmDGrid.DrawGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);

var Index:Integer; CaptionRect, SkRect:TRect:TRect; ImgTitle:string;

begin

// если список не пуст

if SketchList.Count<>0 then begin

//вычисляем индекс изображения в списке

Index:=ARow*DrawGrid.ColCount+ACol;

//если ячейка не пустая

if Index<SketchList.Count then begin //рисуем ячейку

with DrawGrid.Canvas do begin

//рисуем бордюр

Pen.Color:=SketchTextColor;

//если ячейка выделена, то цвет фона SelectBrdColor

if gdSelected in State then Brush.Color:=SelectBrdColor else Brush.Color:=BorderColor; //иначе BorderColor Rectangle(Rect);

Лабораторные работы по информатике для специальности «Моделирование и исследование операций в организационно-технических системах»

//зона эскиза изображения

Brush.Color:=SketchBkColor;

Rectangle(Rect.Left+BorderSize,

Rect.Top+BorderSize, Rect.Right-BorderSize,

Rect.Top+(Rect.Right - Rect.Left)-BorderSize);

//вычисляем область вывода эскиза

SkRect.Left:=Rect.Left+BorderSize;

SkRect.Right:=Rect.Right-BorderSize;

SkRect.Top:=Rect.Top+BorderSize;

SkRect.Bottom:=SkRect.Top + SkRect.Right-SkRect.Left;

{печать эскиза с центрированием по вертикали и горизонтали}

Draw(Rect.Left + (CellWidthTBitmap(SketchList.Objects[Index]).Width) div 2, Rect.Top + (CellWidth – TBitmap(SketchList.Objects[Index]).Height) div 2, TBitmap(SketchList.Objects[Index]));

//зона текста //вычисляем размер области для вывода текста

CaptionRect.Left:=Rect.Left; CaptionRect.Top:= Rect.Bottom - 15; CaptionRect.Right:=Rect.Right; CaptionRect.Bottom:=Rect.Bottom; //устанавливаем цвет для вывода текста

Brush.Color:=BorderColor;

Font.Color:=SketchTextColor;

Rectangle(CaptionRect);

//вывод подписи для картинки (по центру) ImgTitle:= ChangeFileExt(ExtractFileName(

SketchList.Strings[Index]), ''); DrawGrid.Canvas.TextRect(CaptionRect,

CaptionRect.Left+(CellWidth-TextWidth(ImgTitle)) div 2, CaptionRect.Top, ImgTitle);

end;{with}

end;{if Index<ImgList.Count} end;{if ImgList.Count<>0}

end;{DrawGridDrawCell}

Запустите программу, убедитесь в правильности ее работы. Примерный вид окна программы приведен на рисунке 18.

Лабораторные работы по информатике для специальности «Моделирование и исследование операций в организационно-технических системах»

Рисунок 18 – Вид окна программы отображающей эскизы в таблице

Для придания программе законченного вида, добавим отображение выбранного изображения в таблице на правой панели формы.

Шаг 8. Добавьте на панель pnCommand компонент TImage (imgPreview). Установите значения свойств Stretch (масштабирование изображения в заданный прямоугольник) и Proportional (сохранение пропорций изображения при масштабировании) равным True (рисунок 19).

Рисунок 19 – Вид формы после добавления компонента imgPreview.

Установите значения всех элементов свойства Anchors равным True, для того, чтобы при изменении размеров панели компонент imgPreview выравнивался пропорционально размерам панели pnCommand.

Создайте обработчик события OnSelectCell (выбор ячейки) для компонента DrawGrid.

procedure TfrmDGrid.DrawGridSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean);

var Index:Integer; begin

//вычисляем индекс изображения в списке

Index:=ARow*DrawGrid.ColCount+ACol;