[ Pobierz całość w formacie PDF ]
.Closing is simply a matter of freeing the list, which has a record count corresponding tothe list size:function TMdListDataSet.InternalRecordCount: Integer;beginResult := fList.Count;end;The only other method is used to save the data of the current record in the record buffer,including the bookmark information.The core data is simply the position of the currentrecord, which matches the list index (and also the bookmark):procedure TMdListDataSet.InternalLoadCurrentRecord (Buffer: PChar);beginPInteger (Buffer)^ := fCurrentRecord;with PMdRecInfo(Buffer + FRecordSize)^ dobeginBookmarkFlag := bfCurrent;Bookmark := fCurrentRecord;end;end;Directory DataThe derived directory dataset class has to provide a way to load the objects in memory whenthe dataset is opened, to define the proper fields, and to read and write the value of thosefields.Of course, it has also a property indicating the directory to work on, or to be moreprecise, the directory plus the file mask used for filtering the files (as in c:\docs\*.txt):typeTMdDirDataset = class(TMdListDataSet)privateFDirectory: string;procedure SetDirectory(const NewDirectory: string);protected// TDataSet virtual methdosprocedure InternalInitFieldDefs; override;procedure SetFieldData(Field: TField; Buffer: Pointer); override;function GetCanModify: Boolean; override;// custom dataset virtual methodsprocedure InternalAfterOpen; override;publicCopyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 2874c18.qxd 7/2/01 4:40 PM Page 811A Directory in a Dataset 811function GetFieldData(Field: TField; Buffer: Pointer): Boolean; override;publishedproperty Directory: string read FDirectory write SetDirectory;end;The GetCanModify function is another virtual method of TDataSet, used to determine if thedataset is read-only.In this case, it simply returns False.Also, we won t have to write any codefor the SetFieldDataprocedure, but we have to define it because it is an abstract virtual method.As I am dealing with a list of objects, the unit includes also a class for those objects.In thiscase, I am working with file data extracted by a TSearchRec buffer by the TFileData classconstructor:typeTFileData = classpublicShortFileName: string;Time: TDateTime;Size: Integer;Attr: Integer;constructor Create (var FileInfo: TSearchRec);end;constructor TFileData.Create (var FileInfo: TSearchRec);beginShortFileName := FileInfo.Name;Time := FileDateToDateTime (FileInfo.Time);Size := FileInfo.Size;Attr := FileInfo.Attr;end;This constructor is called for each folder while opening the dataset:procedure TMdDirDataset.InternalAfterOpen;varAttr: Integer;FileInfo: TSearchRec;FileData: TFileData;begin// scan all filesAttr := faAnyFile;FList.Clear;if SysUtils.FindFirst(fDirectory, Attr, FileInfo) = 0 thenrepeatFileData := TFileData.Create (FileInfo);FList.Add (FileData);until SysUtils.FindNext(FileInfo) 0;SysUtils.FindClose(FileInfo);end;Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 2874c18.qxd 7/2/01 4:40 PM Page 812812 Chapter 18 " Writing Database ComponentsThe next step is to define the fields of the dataset, which in this case are fixed and dependon the available directory data:procedure TMdDirDataset.InternalInitFieldDefs;beginif fDirectory =   thenraise EMdDataSetError.Create ( Missing directory );// field definitionsFieldDefs.Clear;FieldDefs.Add ( FileName , ftString, 40, True);FieldDefs.Add ( TimeStamp , ftDateTime);FieldDefs.Add ( Size , ftInteger);FieldDefs.Add ( Attributes , ftString, 3);FieldDefs.Add ( Folder , ftBoolean);end;Finally, the component has to move the data from the object of the list referenced by thecurrent record buffer (the ActiveBuffer value) to each field of the dataset, as requested bythe GetFieldData method.This function uses either Move or StrCopy, depending on the datatype and does some conversions for the attributes codes (H for hidden, R for read-only, andS for system) extracted from the related flags and used also to determine whether a file isactually a folder.Here is the code:function TMdDirDataset.GetFieldData (Field: TField; Buffer: Pointer): Boolean;varFileData: TFileData;Bool1: WordBool;strAttr: string;t: TDateTimeRec;beginFileData := fList [PInteger(ActiveBuffer)^] as TFileData;case Field.Index of0: // filenameStrCopy (Buffer, pchar(FileData.ShortFileName));1: // timestampbegint := DateTimeToNative (ftdatetime, FileData.Time);Move (t, Buffer^, sizeof (TDateTime));end;2: // sizeMove (FileData.Size, Buffer^, sizeof (Integer));3: // attributesbeginstrAttr :=   ;if (FileData.Attr and SysUtils.faReadOnly) > 0 thenstrAttr [1] :=  R ;Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 2874c18.qxd 7/2/01 4:40 PM Page 813A Directory in a Dataset 813if (FileData.Attr and SysUtils.faSysFile) > 0 thenstrAttr [2] :=  S ;if (FileData.Attr and SysUtils.faHidden) > 0 thenstrAttr [3] :=  H ;StrCopy (Buffer, pchar(strAttr));end;4: // folderbeginBool1 := FileData.Attr and SysUtils.faDirectory > 0;Move (Bool1, Buffer^, sizeof (WordBool));end;end; // caseResult := True;end;The tricky part in writing this code was figuring out the internal format of dates storedwithin date/time fields.This is not the common TDateTime format used by Delphi, and noteven the internal TTimeStamp, but what is called the internally called the  native date timeformat.I ve written a conversion function cloning one I ve found in the VCL code for thedate/time fields:function DateTimeToNative(DataType: TFieldType; Data: TDateTime): TDateTimeRec;varTimeStamp: TTimeStamp;beginTimeStamp := DateTimeToTimeStamp(Data);case DataType offtDate: Result.Date := TimeStamp.Date;ftTime: Result.Time := TimeStamp.Time;elseResult.DateTime := TimeStampToMSecs(TimeStamp);end;end;With this dataset available, building the demo program (shown in Figure 18.7) was simplya matter of connecting a DBGrid component to it and adding a folder-selection component,Delphi 6 s ShellTreeView control.This control is set up to work only on files, by setting itsRoot property to C:\.When the user selects a new folder, the OnChange event handler of theShellTreeView control refreshes the dataset.Copyright ©2001 SYBEX, Inc., Alameda, CA www.sybex.com 2874c18.qxd 7/2/01 4:40 PM Page 814814 Chapter 18 " Writing Database ComponentsFI GURE 18.7:The output of the DirDemoexample, which uses arather unusual dataset,showing directory data.procedure TForm1.ShellTreeView1Change(Sender: TObject; Node: TTreeNode);beginMdDirDataset1.Close;MdDirDataset1.Directory := ShellTreeView1.Path +  \*.* ;MdDirDataset1.Open;end;What s Next?In this chapter we ve delved inside Delphi s database architecture, by first examining thedevelopment of data-aware controls and then studying the internals of the TDataSet class towrite a couple of custom dataset components [ Pobierz caÅ‚ość w formacie PDF ]

  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • andsol.htw.pl