Link to home
Start Free TrialLog in
Avatar of DelphiRulez
DelphiRulez

asked on

Streaming Objects to File ?

I am using Delphi 2010. I am creating a small application to create a Quiz. I have created my own unit (UntCommon) which includes the following classes (Objects)

TQuiz
TQuestions
TQuestion

Question 1: Why am I getting the error message

"[DCC Error] UntCommon.pas(46): E2188 Published property 'Items' cannot be of type ARRAY"

for the "Items" property  of the TQuestions class?

Question 2: How can I save a Quiz to file (possibly stream) it in somekind of binary format. I would like the answer for each question to be encrypted ( I will work on that later), but for now, im not worried about anything being hacked or readable in the file....but it would be nice to be able to stream it as binary.

I have created two procedures in the TQuiz class (commented out).

Procedure SaveToFile(FileName: String);
Procedure LoadFromFile(FileName: String);

Question 3: Do you see anything else wrong with my code? Most of it was pieced together from help i found using google.

Thanks

unit UntCommon;

interface

uses Classes, Contnrs, Graphics;

type

TQuizType = (qtTrueFalse, qtMultipleChoice, qtFillBlanks, qtAll);

TQuestion = class(TObject)
 private
  fQuestion: String;
  fAnswer: String;
  fAnswers: TStringList;
  fImage: TPicture;
  procedure SetQuestion(Value: String);
  procedure SetAnswer(Value: String);
  procedure SetAnswers(Value: TStrings);
  procedure SetImage(Value: TPicture);
  function GetQuestion: String;
  function GetAnswer: String;
  function GetAnswers: TStrings;
  function GetImage: TPicture;
 public
  constructor Create;
  destructor Destroy;override;
 published
  property Question: String read GetQuestion write SetQuestion;
  property Answer: String read GetAnswer write SetAnswer;
  property Answers: TStrings read GetAnswers write SetAnswers;
  property Image: TPicture read GetImage write SetImage;
end;

TQuestions = class(TObjectList)
 private
  function GetItems(Index: Integer): TQuestion;
  procedure SetItems(Index: Integer; value: TQuestion);
 public
  constructor Create;
  function Add(value: TQuestion): Integer;
  function IndexOf(value: TQuestion): Integer;
  procedure Insert(Index: Integer; value: TQuestion);
  function Remove(value: TQuestion): Integer;
 published
  property Items[Index: Integer]: TQuestion read GetItems write SetItems; default;
end;

TQuiz = class(TObject)
 private
  fTitle: String;
  fType: TQuizType;
  fAuthor: String;
  fQuestions: TQuestions;
  procedure SetTitle(Value: String);
  procedure SetType(Value: TQuizType);
  procedure SetAuthor(Value: String);
  procedure SetQuestions(Value: TQuestions);
  function GetTitle: String;
  function GetType: TQuizType;
  function GetAuthor: String;
  function GetQuestions: TQuestions;
 public
  constructor Create;
  destructor Destroy;override;
  //procedure SaveToFile(FileName: String);
  //procedure LoadToFile(FileName: String);
 published
 property Title: String read GetTitle write SetTitle;
 property QuizType: TQuizType read GetType write SetType;
 property Author: String read GetAuthor write SetAuthor;
 property Questions: TQuestions read GetQuestions write SetQuestions;
end;

implementation

{********** TQuestion **********}

procedure TQuestion.SetQuestion(Value: String);
begin
 if fQuestion <> Value then
  fQuestion:= Value;
end;

procedure TQuestion.SetAnswer(Value: String);
begin
 if fAnswer <> Value then
  fAnswer:= Value;
end;

procedure TQuestion.SetAnswers(Value: TStrings);
begin
  fAnswers.Assign(Value);
end;

procedure TQuestion.SetImage(Value: TPicture);
begin
 fImage.Assign(Value);
end;

function TQuestion.GetQuestion: String;
begin
 result:= fQuestion;
end;

function TQuestion.GetAnswer: String;
begin
 result:= fAnswer;
end;

function TQuestion.GetAnswers: TStrings;
begin
 result.Assign(fAnswers);
end;

function TQuestion.GetImage: TPicture;
begin
 result.Assign(fImage);
end;

constructor TQuestion.Create;
begin
 inherited Create;
 fAnswers:= TSTringList.Create;
 fImage:= TPicture.Create;
 fImage:= nil;
end;

destructor TQuestion.Destroy;
begin
 fImage.Free;
 fAnswers.Free;
 inherited Destroy;
end;

{********** TQUESTIONS **********}

constructor TQuestions.Create;
begin
 inherited Create(true);
end;

function TQuestions.Add(value: TQuestion): Integer;
begin
 Result := inherited Add(value);
end;

function TQuestions.GetItems(Index: Integer): TQuestion;
begin
 Result := TQuestion(inherited Items[Index]);
end;

function TQuestions.IndexOf(value: TQuestion): Integer;
begin
 Result := inherited IndexOf(value);
end;

procedure TQuestions.Insert(Index: Integer; value: TQuestion);
begin
 inherited Insert(Index, value);
end;

function TQuestions.Remove(value: TQuestion): Integer;
begin
 Result := inherited Remove(value);
end;

procedure TQuestions.SetItems(Index: Integer; value: TQuestion);
begin
 inherited Items[Index] := value;
end;

{********** TQUIZ **********}

procedure TQuiz.SetTitle(Value: String);
begin
 if fTitle <> Value then
  fTitle:= Value;
end;

function TQuiz.GetTitle: String;
begin
 result:= fTitle;
end;

procedure TQuiz.SetType(Value: TQuizType);
begin
 if fType <> Value then
  fType:= Value;
end;

function TQuiz.GetType: TQuizType;
begin
 result:= fType;
end;

procedure TQuiz.SetAuthor(Value: String);
begin
 if fAuthor <> Value then
  fAuthor:= Value;
end;

function TQuiz.GetAuthor: String;
begin
 result:= fAuthor;
end;

procedure TQuiz.SetQuestions(Value: TQuestions);
begin
 fQuestions.Assign(Value);
end;

function TQuiz.GetQuestions: TQuestions;
begin
 result.assign(fQuestions);
end;

constructor TQuiz.Create;
begin
 inherited Create;
 fQuestions:= TQuestions.Create;
 fQuestions.OwnsObjects:= True;
end;

destructor TQuiz.Destroy;
begin
 fQuestions.Free;
 inherited Destroy;
end;

end.

Open in new window

SOLUTION
Avatar of ebob42
ebob42
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Ferruccio Accalai
For the Q1
property Items[Index: Integer]
should be
property Items(Index: Integer)
Avatar of DelphiRulez
DelphiRulez

ASKER

Not sure if I should use Memory Stream or file streams. Which is the best?

procedure TQuiz.SaveToFile(FileName: String);
 var
 AStr: TFileStream;
begin
 AStr:= TFileStream.Create(FileName, fmOpenWrite);
 //
 AStr.Free;
end;

procedure TQuiz.LoadToFile(FileName: String);
 var
 AStr: TFileStream;
begin
 AStr:= TFileStream.Create(FileName, fmOpenRead);
 //
 AStr.Free;
end;
I would use FileStream, or a plan TextFile that you can read and write as well to.
well, im still waiting on the SaveToFIle and LoadFrom File procedures

I may have them written before i get a answer from you experts (just from info im gathering from google and EE Search)


procedure TQuiz.SaveToFile(FileName: String);
 var
 AStr: TFileStream;
 I: Integer;
begin
 AStr:= TFileStream.Create(FileName, fmOpenWrite);
 WriteStreamInt(AStr, Questions.Count);
 for I:= 0 to  Questions.Count-1 do
 begin
  WriteStreamStr(AStr, TQuestion(Questions[I]).fQuestion);
    //write rest of question data here
 end;
 AStr.Free;
end;

procedure TQuiz.LoadFromFile(FileName: String);
 var
 AStr: TFileStream;
 QCount, I: Integer;
 AQuestion: TQuestion;
begin
 AStr:= TFileStream.Create(FileName, fmOpenRead);
 QCount:= ReadStreamInt(AStr);
 for I:= 0 to QCount-1 do
 begin
  AQuestion:= TQuestion.Create;
  AQuestion.fQuestion:= ReadStreamStr(AStr);
   //read rest of question data here
  Questions.Add(AQuestion);
 end;
 AStr.Free;
end;


procedure WriteStreamStr(Stream : TStream; Str : string);
var
  StrLen : integer;
begin
 StrLen := Length(Str);
 WriteStreamInt(Stream, StrLen);
 Stream.Write(Str[1], StrLen);
end;

function ReadStreamStr(Stream : TStream) : string;
var
  StrLen : integer;
begin
  StrLen := ReadStreamInt(Stream);
  if StrLen > -1 then begin
    SetLength(Result, StrLen);
    Stream.Read(Result[1], StrLen);
    end
  else
    Result := '';
end;


procedure WriteStreamInt(Stream : TStream; Num : integer);
begin
 Stream.Write(Num, SizeOf(Integer));
end;

function ReadStreamInt(Stream : TStream) : integer;
begin
 if Stream.Read(Result, SizeOf(Integer)) < SizeOf(Integer) then
  Result := -1;
end;

ok, all i have left to write is the Streaming of the TPicture (Not sure if this is do-able or not) .

of course, none of this is tested. Its just compiling so far.  Anyone see any other mistakes or problems i have not foreseen?????????  Can anyone write the code to stream a TPicture?

I need to be able to handle all registered image classes within Delphi (bmp, jpg, gif, png, ect).

Do i need to store an extension, size, ect in the stream????????



procedure TQuiz.SaveToFile(FileName: String);
 var
 AStr: TFileStream;
 I, J: Integer;
begin
 AStr:= TFileStream.Create(FileName, fmOpenWrite);
 WriteStreamStr(AStr, Title);
 WriteStreamInt(AStr, Integer(QuizType));
 WriteStreamStr(AStr, Author);
 WriteStreamInt(AStr, Questions.Count);
 for I:= 0 to  Questions.Count-1 do
 begin
  WriteStreamStr(AStr, TQuestion(Questions[I]).fQuestion);
  WriteStreamStr(AStr, TQuestion(Questions[I]).fAnswer);
  WriteStreamInt(AStr, TQuestion(Questions[I]).fAnswers.Count);
  for J:= 0 to TQuestion(Questions[I]).fAnswers.Count - 1 do
  begin
   WriteStreamStr(AStr, TQuestion(Questions[I]).fAnswers[J]);
  end;
  //write the TPicture to Stream
 end;
 AStr.Free;
end;

procedure TQuiz.LoadFromFile(FileName: String);
 var
 AStr: TFileStream;
 QCount, ACOunt, I: Integer;
 AQuestion: TQuestion;
  J: Integer;
begin
 AStr:= TFileStream.Create(FileName, fmOpenRead);
 Title:= ReadStreamStr(AStr);
 QuizType:= TQuizType(ReadStreamInt(AStr));
 Author:= ReadStreamStr(AStr);
 QCount:= ReadStreamInt(AStr);
 for I:= 0 to QCount-1 do
 begin
  AQuestion:= TQuestion.Create;
  AQuestion.fQuestion:= ReadStreamStr(AStr);
  AQuestion.fAnswer:= ReadStreamStr(AStr);
  ACount:= ReadStreamInt(AStr);
  for J := 0 to ACount - 1 do
  begin
   AQuestion.fAnswers.Add(ReadStreamStr(AStr));
  end;
  //read the TPicture from Stream
  Questions.Add(AQuestion);
 end;
 AStr.Free;
end;

function Encrypt(const S: String; Key: Word): String;
var
  I: byte;
begin
  SetLength(Result, Length(S));
  for I := 1 to Length(S) do
  begin
   Result[I] := char(byte(S[I]) xor (Key shr 8));
   Key := (byte(Result[I]) + Key) * C1 + C2;
  end;
end;

function Decrypt(const S: String; Key: Word): String;
var
  I: byte;
begin
 SetLength(Result, Length(S));
 for I := 1 to Length(S) do
 begin
  Result[I] := char(byte(S[I]) xor (Key shr 8));
  Key := (byte(S[I]) + Key) * C1 + C2;
 end;
end;

procedure WriteStreamStr(Stream : TStream; Str : string);
var
  StrLen : integer;
begin
 StrLen := Length(Str);
 WriteStreamInt(Stream, StrLen);
 Stream.Write(Str[1], StrLen);
end;

function ReadStreamStr(Stream : TStream) : string;
var
  StrLen : integer;
begin
  StrLen := ReadStreamInt(Stream);
  if StrLen > -1 then begin
    SetLength(Result, StrLen);
    Stream.Read(Result[1], StrLen);
    end
  else
    Result := '';
end;


procedure WriteStreamInt(Stream : TStream; Num : integer);
begin
 Stream.Write(Num, SizeOf(Integer));
end;

function ReadStreamInt(Stream : TStream) : integer;
begin
 if Stream.Read(Result, SizeOf(Integer)) < SizeOf(Integer) then
  Result := -1;
end;
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial