Проект будет состоять из двух модулей (одна форма), потому что отдельный модуль (Kinto) выделен для описания класса TKentavr.
Еще один двухмодульный проект, разработка и создание которого подробно описаны, Вы найдете здесь
1-й этап: открывать файлы с картинками, создавать описания и названия к этим картинкам и сохранять в памяти в виде списка. Названия картинок помещать с окно списка ListBox, причем при щелчке по названию картинки - показывать картинку и ее описание.
2-й этап: добавить операции: сохранения созданного в памяти списка в файле на диске, чтения такого списка из файла, удаления выделенного элемента списка.
unit Kinto; interface uses Graphics, Classes; type TKentavr = Class private // доступно только в этом модуле FBMP1: TBitMap; FOpisan: String; FNazvan: String; FErr: Boolean; public // доступно во всем проекте property Opisan: String read FOpisan write FOpisan; property Nazvan: String read FNazvan write FNazvan; property BMP1: TBitMap read FBMP1 write FBMP1; property Err: Boolean read FErr; constructor Create; destructor Destroy; override; procedure Assign(Source: TPersistent); procedure SaveToStream(Stream: TStream); procedure LoadFromStream(Stream: TStream); end; implementation constructor TKentavr.Create; begin inherited; FBMP1 := TBitmap.Create; FErr := false; end; destructor TKentavr.Destroy; begin FBMP1.Free; inherited; end; procedure TKentavr.Assign(Source: TPersistent); begin FBMP1.Assign(Source); end; procedure TKentavr.SaveToStream(Stream: TStream); Var Len: Integer; begin Len := Length(FNazvan); //длина строки FNazvan Stream.Write(Len,4);//записываем длину FNazvan в поток Stream. // Поток в данном случае - параметр метода, поэтому реально // существующий поток должен быть передан при вызове метода. Stream.Write(FNazvan[1],Len);// записываем FNazvan Len := Length(FOpisan); //длина строки FOpisan Stream.Write(Len,4);//записываем длину FOpisan Stream.Write(FOpisan[1],Len);// записываем FOpisan FBMP1.SaveToStream(Stream); end; procedure TKentavr.LoadFromStream(Stream: TStream); Var Len, read1: Integer; begin read1:= Stream.Read(Len,4); //из потока нужно прочесть 4 байта, и поместить их в //переменную Len. Это – длина строки, которая будет прочтена. if read1 < 4 then // когда файл закончится read1 будет = 0 begin FErr := true; exit; end else FErr := false; SetLength(FNazvan,Len); //установим размер строки = Len байт Stream.Read(FNazvan[1],Len); //Читаем из потока Len байт, помещаем //в строку FNazvan, начиная с 1-го символа строки. Stream.Read(Len,4); //из потока прочтено 4 байта, помещено в //переменную Len. Это – длина 2-й строки, которая будет прочтена. SetLength(FOpisan,Len); //установим размер строки = Len байт Stream.Read(FOpisan[1],Len); //Читаем из потока Len байт, помещаем //в строку FNazvan, начиная с 1-го символа строки. FBMP1.LoadFromStream(Stream); end; end.
constructor Create; - в раздел public и его реализацию в раздел implementation модуля Kinto: constructor TKentavr.Create; begin inherited; FBMP1 := TBitmap.Create; FErr := false; // end;
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Menus, ComCtrls, StdCtrls, ExtCtrls, ExtDlgs; type TForm1 = class(TForm) ListBox1: TListBox; OpenPictureDialog1: TOpenPictureDialog; Image1: TImage; Label2: TLabel; memOpisan: TMemo; MainMenu1: TMainMenu; File1: TMenuItem; Add: TMenuItem; Delete: TMenuItem; Read_Picture: TMenuItem; ReadList: TMenuItem; WriteList: TMenuItem; Exit2: TMenuItem; Label1: TLabel; edNazvan: TEdit; SD1: TSaveDialog; OD1: TOpenDialog; procedure ListBox1Click(Sender: TObject); procedure Read_PictureClick(Sender: TObject); procedure Exit2Click(Sender: TObject); procedure AddClick(Sender: TObject); procedure WriteListClick(Sender: TObject); procedure ReadListClick(Sender: TObject); procedure DeleteClick(Sender: TObject); private { Private declarations } Procedure Maxi; public { Public declarations } end; var Form1: TForm1; FName : String; implementation uses Kinto; {$R *.dfm} Var Ind1: Integer; Kent,Kent2: TKentavr; Function Max(a,b: Integer):Integer; begin // Возвращает наибольшее из значений параметров a или b If A > B then result := a else result := b; end; Procedure TForm1.Maxi; Var Maxa: Integer; begin // Определяет клиентские размеры формы – т к размеры картинки // меняются maxa := Image1.left+Image1.width + 10; // координата правой границы картинки ClientWidth := maxa + 2; maxa := Max(edNazvan.Top + edNazvan.height,//Координата низа edNazvan Image1.Top + Image1.Height); //Координата низа Image1 ClientHeight := Maxa+30;// Учет наличия полосы StatusBar1 end; procedure TForm1.ListBox1Click(Sender: TObject); Var Ind: Integer; //при щелчке по строке ListBox1 показываем картинку, // связанную с этой строкой и содержимое полей объекта begin Ind := ListBox1.ItemIndex; // Индекс выделенной строки If Ind < 0 then begin beep; ShowMessage('Не выделен элемент'); exit; end; //ссылку на объект, который хранится в //ListBox1.Items.Objects[Ind] // копируем в переменную-объект Kent, затем – поле Kent.FBMP копируем // в свойство .Picture.BitMap компонента Image1 // в результате картинка появляется на форме. Kent:= ListBox1.Items.Objects[Ind] as TKentavr; Image1.Picture.Bitmap.Assign(Kent.BMP1); Maxi; //Перестраиваем размеры формы, т к сменилась картинка. MemOpisan.Clear; MemOpisan.Text := Kent.Opisan; //Заполняем текст MemOpisan edNazvan.Text := Kent.Nazvan; //ListBox1.Items[Ind]; end; procedure TForm1.Read_PictureClick(Sender: TObject); //Выбрать файл с картиной begin If OpenPictureDialog1.Execute then //диалог позволяет выбрать файл. begin Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName); Maxi; //вычисляем новые клиентские размеры формы, чтобы вся картинка была видна. end; end; procedure TForm1.Exit2Click(Sender: TObject); begin //выход из программы Application.Terminate; end; procedure TForm1.AddClick(Sender: TObject); begin // Добавить сформированный объект Kent2 в список Kent2 := TKentavr.Create; Kent2.Assign(Image1.Picture.Bitmap); Kent2.Opisan := MemOpisan.Text; Kent2.Nazvan := edNazvan.Text; Ind1:=ListBox1.Items.AddObject(edNazvan.text,Kent2); ListBox1.ItemIndex := Ind1; end; procedure TForm1.WriteListClick(Sender: TObject); //вызывается щелчком по пункту меню «Записать список в файл» // списки храним в файлах с расширением .lst Var ii: Integer; s1,s2: String; Len: Integer; FS: TFileStream; begin if ListBox1.Count = 0 then begin showmessage('Список пустой. Не записываю'); exit; end; if SD1.Execute then FName:= SD1.FileName else exit; FS := TFileStream.Create(FName,fmCreate); //создаем поток для записи, связанный с файлом for ii:=1 to ListBox1.Count do begin Kent:= ListBox1.Items.Objects[ii-1] as TKentavr; //циклически меняется переменная ii от 1 до числа элементов в списке. //Переменной Kent (объявлена статически, поэтому создавать ее не надо) //присваивается значение (ii-1)-го объекта списка, причем результат //преобразуется к типу TKentavr при помощи оператора as TKentavr. Kent.SaveToStream(FS); end; FS.Free; //закрываем и освобождаем поток. ListBox1.Clear; edNazvan.Clear; memOpisan.Clear; end; procedure TForm1.ReadListClick(Sender: TObject); //Щелчок по пункту меню «Прочесть список из файла» //- чтение данных из потока. Var s1,s2,s3: String; Kent: TKentavr; Len,read1: Integer; FS: TFileStream; begin if OD1.Execute then FName:= OD1.FileName else exit; FS := TFileStream.Create(FName,fmOpenRead); //создан объект класса TFileStream только для чтения ListBox1.Clear; // чистим список. Kent := TKentavr.Create; While not Kent.Err do //до тех пор, пока что-то прочтено begin Kent.LoadFromStream(FS); if Kent.Err then break; ListBox1.Items.AddObject(Kent.Nazvan,Kent); Kent := TKentavr.Create; end; Kent.Free; ListBox1.ItemIndex := 0; //выделим первый элемент списка (индекс =0) // ListBox1Click(Sender); //исполним процедуру щелчка по списку ListBox1 FS.Free; //освобождаем поток, так как он не нужен (всё прочтено) end; procedure TForm1.DeleteClick(Sender: TObject); begin ListBox1.Items.Objects[ListBox1.ItemIndex].Free; // освобождаем объект. ListBox1.DeleteSelected; // удаляем выделенный элемент end; end.