Here is a semi-practical example demonstrating the usefulness of a DocFile. A very common requirement for an application that uses a TreeView, is to save the TreeView to disk.
Form many people the TreeView's SaveToFile method is just not good enough as it only saves the tree structure. All TTreeNode information like images, data etc is lost.
To keep the example short I've used my TDocFile classes to simplify things.
Saving to a DocFile
procedure Save_CallBack( Node : TTreeNode; pData : pointer );
var
stor : TDocFileStorage;
subStor : TDocFileStorage;
strmImages : TDocFileStream;
begin
{End of recursion (base case)}
if( (Node = nil) or (pData = nil) ) then
Exit;
stor := TDocFileStorage(pData);
{Create a storage for this node
NB Remember the limits on a storage element's name,
(31 chars max etc...)}
subStor := stor.CreateStorage( Node.Text, MY_STGM_CREATE );
{Was storage created}
if( subStor = nil ) then
begin
ShowMessage( 'Error creating sub-storage' );
Exit;
end;
{Open the stream for saving the image info to}
strmImages := subStor.CreateStream( 'Images', MY_STGM_CREATE );
{Images stream created?}
if( strmImages = nil ) then
begin
ShowMessage( 'Error Creating stream' )
end
else begin
{Save image and selected index}
strmImages.WriteString( IntToStr( Node.ImageIndex ) + #13#10 +
IntToStr( Node.SelectedIndex )
);
end;
{Save all children}
if( Node.GetFirstChild <> nil ) then
Save_CallBack( Node.GetFirstChild, subStor );
{Save all siblings}
if( Node.GetNextSibling <> nil ) then
Save_CallBack( Node.GetNextSibling, stor );
strmImages.Free;
subStor.Free;
end;
procedure TForm1.but_SaveClick(Sender: TObject);
var
storFile : TDocFileStorage;
begin
{Create the file}
storFile := CreateDocFile( ExtractFilePath( Application.ExeName ) + '\z.ole',
MY_STGM_CREATE
);
if( storFile = nil ) then
begin
ShowMessage( 'Cant create file' );
Exit;
end;
{Start saving}
Save_CallBack( tv_eg5.Items[ 0 ], storFile );
{Done}
storFile.Free;
end;
When the save button is clicked the following occurs
The Save_CallBack function works as follows
Loading the data back from the DocFile is slightly (only just) more complex than saving it.
procedure Load_CallBack( Node : TTreeNode; pData : pointer );
var
stor : TDocFileStorage;
substor : TDocFileStorage;
strmImages : TDocFileStream;
begin
stor := TDocFileStorage(pData);
{Open the storage for this element}
substor := stor.OpenStorage( Node.Text, MY_STGM_OPEN );
{Storage opened?}
if( substor = nil ) then
begin
ShowMessage( 'Cant open storage ' + Node.Text );
Exit;
end;
{Open the images stream}
strmImages := substor.OpenStream( 'Images', MY_STGM_OPEN );
{Stream open?}
if( strmImages <> nil ) then
begin
with TStringList.Create do
begin
{Load the stream's data into a TString List}
LoadFromStream( strmImages );
if( Count > 0 ) then
begin
{Get the saved image index}
Node.ImageIndex := StrToInt( Strings[ 0 ] );
if( Count > 1 ) then
{Get the saved selected index}
Node.SelectedIndex := StrToInt( Strings[ 1 ] );
end;
Free;
end;
{Close the stream}
strmImages.Free;
end;
{Enum all sub-elements}
substor.EnumElements( Form1.LoadName_callback, substor );
{Done with storage}
substor.Free;
end;
function TForm1.LoadName_callback( sElementName : WideString;
dwType : DWORD;
pData : pointer
) : boolean;
var
Node : TTreeNode;
OldNode : TTreeNode;
begin
{Continue enum}
Result := true;
{Only interested in storages}
if( dwType <> STGTY_STORAGE ) then
Exit;
{Save the node that is currently selected}
OldNode := tv_eg5.Selected;
{Add a new node for this element}
Node := tv_eg5.Items.AddChild( tv_eg5.Selected, sElementName );
{Select new node}
Node.Selected := true;
{Load data and all sub-elements}
Load_CallBack( Node, pData );
{Select old node again}
if( OldNode <> nil ) then
OldNode.Selected := true;
end;
procedure TForm1.but_LoadClick(Sender: TObject);
var
storFile : TDocFileStorage;
begin
{Open the file}
storFile := OpenDocFile( ExtractFilePath( Application.ExeName ) + '\z.ole',
MY_STGM_OPEN
);
{Was the DocFile opened}
if( storFile = nil ) then
begin
ShowMessage( 'Cant open file' );
Exit;
end;
{Remove all tree nodes}
tv_eg5.Items.Clear;
{Enum all root level elements in the storage file}
storFile.EnumElements( LoadName_callback, storFile );
{Done}
storFile.Free;
end;
As you can see there are three functions involved here, the loading (and recursion) takes place beteen LoadName_callback and Load_CallBack.
The following picture depicts the flow of execution
When the load button is clicked
LoadName_callback
Load_CallBack
This example does not show saving of the TTreeNode's data to the DocFile.
The reason for that is that saving the TTreeNode's data is very similar to
saving the image info to the stream. Natrally the exact method will be
differant depending on what type of data TTreeNode.Data represents.
The full source code for this example is available as a zip file on the source code page
All information on these www pages is copyright (©) 1997 Andre .v.d. Merwe And may not be copied or mirrored without my permission.