![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как лучше хранить координаты точек и изображения в файле? [D7, WinXP]
Дмитрий_177 © (2006-04-06 00:45:00)Я уже задавал этот вопрос, но тему уже удалили... Мне Джо показал пример класса по вопосу:
unit PointsUtils;
interface
uses Windows, SysUtils, Classes;
type
TPoints = class
private
FList: TList;
procedure SetItems(Index: Integer; const Value: TPoint);
function GetItems(Index: Integer): TPoint;
function GetCount: Integer;
public
constructor Create();
destructor Destroy; override;
function Add (X,Y: Integer): Integer; overload;
function Add (APoint: TPoint): Integer; overload;
property Count: Integer read GetCount;
property Items[Index: Integer]: TPoint read GetItems write SetItems; default;
procedure Clear;
procedure SaveToStream (AStream: TStream);
procedure SaveToFile (AFileName: string);
procedure LoadFromStream (AStream: TStream);
procedure LoadFromFile (AFileName: string);
end;
implementation
type
PPoint = ^TPoint;
{ TPoints }
function TPoints.Add(X, Y: Integer): Integer;
var
Pt: TPoint;
begin
Pt.X := X;
Pt.Y := Y;
Result := Add (Pt)
end;
function TPoints.Add(APoint: TPoint): Integer;
var
NewPt: PPoint;
begin
GetMem (NewPt,SizeOf(TPoint));
NewPt^ := APoint;
Result := FList.Add(NewPt)
end;
procedure TPoints.Clear;
var
I: Integer;
begin
for I := Count - 1 downto 0 do
FreeMem (FList[I]);
FList.Clear;
end;
constructor TPoints.Create;
begin
inherited;
FList := TList.Create;
end;
destructor TPoints.Destroy;
begin
Clear;
FList.Free;
inherited;
end;
function TPoints.GetCount: Integer;
begin
Result := FList.Count
end;
function TPoints.GetItems(Index: Integer): TPoint;
begin
Result := PPoint(FList[Index])^
end;
procedure TPoints.LoadFromFile(AFileName: string);
var
Fs: TFileStream;
begin
Fs := TFileStream.Create(AFileName,fmOpenRead);
try
LoadFromStream(Fs);
finally
Fs.Free;
end;
end;
procedure TPoints.LoadFromStream(AStream: TStream);
var
I,
Cnt: Integer;
Pt: TPoint;
begin
Clear;
AStream.Read(Cnt,SizeOf(Cnt));
for I := 0 to Cnt-1 do
begin
AStream.Read(Pt,SizeOf(Pt));
Add (Pt)
end;
end;
procedure TPoints.SaveToFile(AFileName: string);
var
Fs: TFileStream;
begin
Fs := TFileStream.Create(AFileName,fmCreate);
try
SaveToStream(Fs);
finally
Fs.Free;
end;
end;
procedure TPoints.SaveToStream(AStream: TStream);
var
I: Integer;
Pt: TPoint;
Cnt: Integer;
begin
// количество точек
Cnt := Count;
AStream.Write(Cnt,SizeOf(Cnt));
// сами точки
for I := 0 to Count - 1 do
begin
Pt := Self[I];
AStream.Write(Pt,SizeOf(TPoint));
end;
end;
procedure TPoints.SetItems(Index: Integer; const Value: TPoint);
begin
PPoint(FList[Index])^ := Value
end;
end.
Пример использования:
---------------------
procedure TForm18.Button1Click(Sender: TObject);
var
APoints: TPoints;
I: Integer;
begin
APoints := TPoints.Create;
try
APoints.Add(10,20);
APoints.Add(30,40);
APoints.Add(50,60);
APoints.SaveToFile('d:\points.dat');
APoints.Clear;
APoints.LoadFromFile ('d:\points.dat');
for I := 0 to APoints.Count - 1 do
ShowMessageFmt('%d,%d',[APoints[I].X,APoints[I].Y]);
finally
APoints.Free;
end;
end;
Но у меня возникло несколько вопросов:
1. Что делает функция Clear; в LoadFromStream и Destroy?
2. Если расширить класс еще с сохранением изображений, так правильно будет?
private
FPictureTop: TPicture;
FPictureBottom: TPicture;
procedure SetPictureTop(const Value: TPicture);
procedure SetPictureBottom(const Value: TPicture);
public
property PictureTop: TPicture read FPictureTop write SetPictureTop;
property PictureBottom: TPicture read FPictureBottom write SetPictureBottom;
end;
...
procedure ...SetPictureTop(const Value: TPicture);
begin
FPictureTop.Assign(Value)
end;
procedure ...SetPictureBottom(const Value: TPicture);
begin
FPictureBottom.Assign(Value)
end;
procedure ...SaveToStream(AStream: TStream);
begin
...
AStream.Write(FPictureTop, SizeOf(FPictureTop));
AStream.Write(FPictureBottom, SizeOf(FPictureBottom));
end;
procedure ...LoadFromStream(AStream: TStream);
begin
...
AStream.Read(FPictureTop, SizeOf(FPictureTop));
AStream.Read(FPictureBottom, SizeOf(FPictureBottom));
end;
Дмитрий_177 (2006-04-12 11:56:00) [1]Название темы уже не соответствует разговору... Создам новую тему.
Дмитрий_177 (2006-04-12 00:40:00) [2]У меня опять как всегда появился еще один вопрос... Со шрифтом я справился но.. есть одно но... Вдруг на компъютере пользователя не окажется такого шрифта, вот я решил еще в файл записывать сам файл шрифта:
type
TMyFile = class
private
FFileFont: TMemoryStream;
procedure SetFileFont(const Value: TFileStream);
protected
procedure SaveToStream (AStream: TStream);
procedure LoadFromStream (AStream: TStream);
public
property FileFont: TFileStream read FFileFont write SetFileFont;
procedure SaveToFile (AFileName: string);
procedure LoadFromFile (AFileName: string);
end;
implementation
constructor TMyFile.Create;
begin
inherited;
FFileFont := TMemoryStream.Create;
end;
destructor TMyFile.Destroy;
begin
FFileFont.Free;
inherited;
end;
procedure TMyFile.SetFileFont(const Value: TFileStream);
begin
FFileFont.LoadFromStream(Value)
end;
procedure TMyFile.SaveToStream (AStream: TStream);
var
Cnt: Int64;
begin
FFileFont.Position := 0;
Cnt := FFileFont.Size;
AStream.Write(Cnt, SizeOf(Cnt));
AStream.CopyFrom(FFileFont, Cnt);
end;
procedure TMyFile.LoadFromStream (AStream: TStream);
var
Cnt: Int64;
begin
AStream.Read(Cnt, SizeOf(Cnt));
FFileFont.CopyFrom(AStream, Cnt);
end;
Вот так правильно будет? Подскажите пожалуйста еще с этим...
Дмитрий_177 (2006-04-11 19:55:00) [3]спасибо большое за помощь =)))
Джо (2006-04-11 19:36:00) [4]> [27] Дмитрий_177 (11.04.06 18:07)
> Почитал... Если честно как сохранять TFont я так и не понял...
> наверно надо так: отдельно сохранять название шрифта, его
> размер и т.д... а потом все это считывать и присваивать
> TFont =)))
Да.
> И еще, если в string нужно и размер сохранять... а в чем
> ненужно? ведь строку то небольшую сохранять буду... может
> ShortString или Char?
Да, если ShortString, то, конечно, длину сохранять не нужно, она известна заранее.
Дмитрий_177 (2006-04-11 19:33:00) [5]Ну так что насчет Дмитрий_177 (11.04.06 18:07) [27]? Мне это очень важно сейчас...
Джо (2006-04-11 18:27:00) [6]> [28] Alarm © (11.04.06 18:14)
> Дмитрий_177 < - > Джо
>
> Ну очень интересная переписка
Рад, что вам понравилась.
> И ведь какой день подряд. Можно было бы организовать это
> и другими способами:(
Нет, нельзя. Я не даю бесплатных консультаций по e-mail (c) кто-то из здешних.
Alarm (2006-04-11 18:14:00) [7]Дмитрий_177 < - > Джо
Ну очень интересная переписка
И ведь какой день подряд. Можно было бы организовать это и другими способами:(
Дмитрий_177 (2006-04-11 18:07:00) [8]Почитал... Если честно как сохранять TFont я так и не понял... наверно надо так: отдельно сохранять название шрифта, его размер и т.д... а потом все это считывать и присваивать TFont =))) И еще, если в string нужно и размер сохранять... а в чем ненужно? ведь строку то небольшую сохранять буду... может ShortString или Char?
Дмитрий_177 (2006-04-11 16:51:00) [9]Спасибо Джо, буду разбираться с классами и объектами... и думать как TFont сохранять =)))
Джо (2006-04-11 16:43:00) [10]> [24] Дмитрий_177 (11.04.06 16:36)
> а вот так непойдет TFont сохранять и загружать? AStream.Write(FFont,
> SizeOf(TFont)); AStream.Read(FFont, SizeOf(FFont));
Не пойдет ни в коем разе. Тебе нужно разобраться с понятиями класса, объекта и т.д. Т.е, таки почитать литературу по языку.
> А еще что скажете по поводу Дмитрий_177 (11.04.06 02:28)
> [20]?
А что тут сказать? Читай книгу, справку. На предмет ООП и его реализации в Делфи.
По поводу "надо разрушить его "Free" а потом заново создать" — не обязательно. Если класс графики не меняется, то нужно
1. В конструкторе создавать экземпляр TBitmap.
2. В деструкторе его разрушать.
3. В методе Set... делать не :=, а Assign.
Дмитрий_177 (2006-04-11 16:36:00) [11]а вот так непойдет TFont сохранять и загружать? AStream.Write(FFont,SizeOf(TFont)); AStream.Read(FFont, SizeOf(FFont));
А еще что скажете по поводу Дмитрий_177 (11.04.06 02:28) [20]?
Джо (2006-04-11 16:22:00) [12]Вообще, возможно, есть смысл немного перепроектировать, раз такое большое кол-во разнородных данных приходится писать/восстанавливать. Можно сделать наследника TComponent с published-свойствами. Тогда можно будет воспользоваться стандартными возможностями TStream.WriteComponent & ReadComponent.
Джо (2006-04-11 16:17:00) [13]> [21] Дмитрий_177 (11.04.06 16:07)
1. Для string нужно. Для TFont вообще нужно отдельное сохранение писать, у него нет SaveToStream.
2. Да, в общем, без разницы.
3. Какой смысл в пустом конструкторе?
Дмитрий_177 (2006-04-11 16:07:00) [14]и еще у меня маленькие вопросики, надеюсь что последние...
1: типы TFont, TRect, String как надо сохранять и считывать? нужно как в сохранении сохранять размер или нет?
2: в этих же типах TFont, TRect, String в процедуре Set... нужно ли писать "const" в скобоках перед Value: "тип"?
3: если мы создаем свой класс в котором все переменные например Integer, нужно ли конструктор писать или ненадо? или нужно хотябы так написать?
constructor TMyClass.Create;
begin
inherited;
end;
Дмитрий_177 (2006-04-11 02:28:00) [15]Значит можно и без "virtual" и без "override" обойтись? как это сделано в конструкторе Create =))) Просто:
constructor TPoints.Create;
begin
inherited;
FList := TList.Create;
end;
или с конструктором особый случай?
А еще я так и не понял как мне очищать изображение =( надо разрушить его "Free" а потом заново создать? А можно например так? FBmp := nil; или какнибудь так?
Джо (2006-04-10 02:21:00) [16]Всё, я спать, приехали :( Короче, то, что я хотел сказать, видно из приведенного исходного текста.
Джо (2006-04-10 02:20:00) [17]> Потому, что у потомка деструктор
Потому, что у потомка конструктор.
Сорри за опечатку.
Джо (2006-04-10 02:19:00) [18]> Почему мы destructor Destroy; перекрываем "override - ом"
> а constructor Create;
Потому, что у потомка деструктор объявлен виртуальным, а деструктор — нет. См. исходный текст класса TObject:
TObject = class
constructor Create;
...
destructor Destroy; virtual;
end;
> -> надо ли перекрывать?
Нет, ибо у потомка (TPoints) они не виртуальные. Объяви их virtual, исходный текст тебе на что даден? :)
В общем, серьезно, почитай об основах ООП, потому, что так можно мучаться этими вопросами постоянно. :)
Дмитрий_177 (2006-04-09 17:48:00) [19]И еще у меня еще вопросик возник, причем из интереса... Вот правда не знаю, даже книгу почитал и всеравно плохо понимаю...=((( Почему мы destructor Destroy; перекрываем "override - ом" а constructor Create; нет? я как понял что тоже надо, вроде как потомок класса TObject... А еще если такая будет ситуация, допустим мы захотим создать новый класс родителем которого будет "TPoints" и добавить туда какое-нибудь свойство например тоже изображение типа TBitmap. Как надо определять новый класс?
TNewPoints = class(TPoints)
private
FBmp: TBitmap;
procedure SetBmp(const Value: TBitmap);
protected
procedure SaveToStream (AStream: TStream); override;
procedure LoadFromStream (AStream: TStream); override; -> надо ли перекрывать? (у меня в TPoints эти процедуры тут, а сохранения в файл вообще нету, т.к. они в TGraphicData)
public
constructor Create; override; -> тут тоже, надо ли перекрывать? вот мне больше всего интересно...
destructor Destroy; override;
property Bmp: TBitmap read FBmp write SetBmp;
procedure Clear; override; -> и тут
end;
implementation
...
constructor TNewPoints.Create;
begin
inherited;
FBmp := TBitmap.Create; // еще я не очень представляю что бы мы тут писали если добавляли свойство например типа intеger? просто inherited; и все? или вообще "Create" с "Destroy" ненужен бы был?
end;
destructor TNewPoints.Destroy;
begin
FBmp.Free;
inherited;
end;
procedure TNewPoints.SetBmp(const Value: TBitmap);
begin
FBmp.Assign(Value)
end;
procedure TNewPoints.Clear; // помоему вообще зря перекрываю... по идее ненадо...
begin
inherited;
//FBmp.Free -> Я думаю так не правильно т.к. разрушит класс в памяти, и при последующей загрузке изображения выдаст ошибку, надо какнибудь просто очистить FBmp, а как не знаю...=((( Или надо убивать а потом создавать заново?
end;
procedure TNewPoints.SaveToStream (AStream: TStream);
var
TempStream: TMemoryStream;
Cnt: Int64;
begin
inherited; -> помоему обязательно нужно написать (чтобы точки из TPoints сохранились)
if Assigned(FBmp) then
begin
TempStream := TMemoryStream.Create;
try
FBmp.SaveToStream(TempStream);
TempStream.Position := 0;
Cnt := TempStream.Size;
AStream.Write(Cnt, SizeOf(Cnt));
AStream.CopyFrom(TempStream, Cnt)
finally
TempStream.Free;
end;
end;
end;
procedure TNewPoints.LoadFromStream (AStream: TStream);
var
Cnt: Int64;
TempStream: TMemoryStream;
begin
inherited; -> и тут помоему тоже обязательно нужно написать (чтобы точки считались)
if Assigned(FBmp) then
begin
AStream.Read(Cnt, SizeOf(Cnt));
TempStream := TMemoryStream.Create;
try
TempStream.CopyFrom(AStream, Cnt);
TempStream.Position := 0;
FBmp.LoadFromStream(TempStream);
finally
TempStream.Free;
end;
end;
end;
Если что не так поправьте меня пожалуйста и подскажите по вопросам которые я задал в тесте программы...
Дмитрий_177 (2006-04-08 02:19:00) [20]Ой, т.е. так:
constructor TGraphicData.Create;
begin
FPictureTop := TBitmap.Create;
FPictureBottom := TBitmap.Create;
FPoints := TPoints.Create;
end;
destructor TGraphicData.Destroy;
begin
DeleteGraphics;
//FPictureTop.Free;
//FPictureBottom.Free; -> тут я не знаю надо ли писать эти строки или нет, по идее их убивает функция "DeleteGraphics", так что я их убрал (закоментировал)
FPoints.Free;
inherited;
end;
procedure TGraphicData.DeleteGraphics;
begin
if Assigned(FPictureTop) then
FreeAndNil(FPictureTop);
if Assigned(FPictureBottom) then
FreeAndNil(FPictureBottom);
end;
procedure TGraphicData.LoadGraphicFromStream(var ABitmap: TBitmap;
AStream: TStream);
var
Cnt: Int64;
TempStream: TMemoryStream;
begin
// if Assigned(ABitmap) then
// ABitmap.Free; -> с этими строками у меня выскакивает ошибка, а без них все нормально работает
if Assigned(ABitmap) then
begin
AStream.Read(Cnt, SizeOf(Cnt));
TempStream := TMemoryStream.Create;
try
TempStream.CopyFrom(AStream, Cnt);
TempStream.Position := 0;
ABitmap.LoadFromStream(TempStream);
finally
TempStream.Free;
end;
end;
end;
procedure TGraphicData.SaveGraphicToStream(ABitmap: TBitmap; AStream: TStream);
var
TempStream: TMemoryStream;
Cnt: Int64;
begin
if Assigned(ABitmap) then
begin
TempStream := TMemoryStream.Create;
try
ABitmap.SaveToStream(TempStream);
TempStream.Position := 0;
Cnt := TempStream.Size;
AStream.Write(Cnt, SizeOf(Cnt));
AStream.CopyFrom(TempStream, Cnt)
finally
TempStream.Free;
end;
end;
end;
Так у меня все работает =))) Но мне еще не понятно правильно ли я сделал эти процедуры, вроде как определять ничего не надо... присвоить и все:
procedure TGraphicData.SetPictureBottom(const Value: TBitmap);
begin
FPictureBottom.Assign(Value);
end;
procedure TGraphicData.SetPictureTop(const Value: TBitmap);
begin
FPictureTop.Assign(Value);
end;