Board index » cppbuilder » Saving component properties from executable

Saving component properties from executable

Hi,

I have a complex component whose properties need to be saved before the
application exits, almost like a save settings sort of thing.  If I create a
TFileStream and WriteComponent(TComponent *Instance) to the stream, will
that save all published property values that are different from default
values?  Also, to read in the component property values upon application
restart, can I override the TComponent::Loaded() method and include a call
to TFileStream::ReadComponent there?  If not, where should the loading be
done in the executable?

Thanks,
Brady

 

Re:Saving component properties from executable


Why not just ammend your component's source code to save and reload its own
properties to a specified file as needed?  Have your component implement its
own custom SaveToStream() and LoadFromStream() methods, then just pass the
TFileStream to the component and let it handle the details internally.

Gambit

"E. Brady Trexler, Ph.D." <edmund.b.trex...@uth.tmc.edu> wrote in message
news:3e4f3581@newsgroups.borland.com...

Quote
> If I create a TFileStream and WriteComponent(TComponent *Instance)
> to the stream, will that save all published property values that are
different
> from default values?

Re:Saving component properties from executable


Hi Remy, thanks for your reply.  Separate functions are a good idea, as they
allow settings to be saved to different files. Can I still use ReadComponent
and WriteComponent in these functions, rather than iterating through all the
properties?

Quote
> Why not just ammend your component's source code to save and reload its
own
> properties to a specified file as needed?  Have your component implement
its
> own custom SaveToStream() and LoadFromStream() methods, then just pass the
> TFileStream to the component and let it handle the details internally.

Re:Saving component properties from executable


Possibly.  I've never used those functions directly myself, I don't know how
they would react when called from inside the component itself.  Typically
it's probably best to just store/restore the individual values you're
actually interested in and let the system handle the rest in its default
manner.

Gambit

"E. Brady Trexler" <edmund.b.trex...@uth.tmc.edu> wrote in message
news:3e500a00$1@newsgroups.borland.com...

Quote
> Hi Remy, thanks for your reply.  Separate functions are a good idea,
> as they allow settings to be saved to different files. Can I still use
> ReadComponent and WriteComponent in these functions, rather
> than iterating through all the properties?

Re:Saving component properties from executable


Quote
Remy wrote:
> Why not just ammend your component's source code to save and reload its own
> properties to a specified file as needed?  Have your component implement its
> own custom SaveToStream() and LoadFromStream() methods, then just pass the
> TFileStream to the component and let it handle the details internally.

Where's a good place to save the component?  I tried with a TMemo descendant
and the Lines property is gone by the time the destructor executes, and even
BeforeDestruction() was too late.  I tried Notification, too.

Re:Saving component properties from executable


I doubt that, considering that the Lines property isn't freed until
TCustomMemo::Destroy, which by law of both Pascal and C++ languages, must
execute AFTER your own destructor, not before it.

Gambit

Quote
"Fishface" <inva...@ddress.ok?> wrote in message

news:3e502b3e$1@newsgroups.borland.com...
Quote
> I tried with a TMemo descendant and the Lines property
> is gone by the time the destructor executes

Re:Saving component properties from executable


Quote
Fishface wrote:
> Where's a good place to save the component?  I tried with a TMemo
> descendant and the Lines property is gone by the time the destructor
> executes, and even BeforeDestruction() was too late.  I tried
>Notification, too.

Well, I mean if it were completely handled by the component and not
at the form level.  I tried DestroyWnd() and DestroyWindowHandle(),
but aren't called unless the control is being recreated.  Hmm-- maybe
something in WndProc()...

Re:Saving component properties from executable


What does your actual code look like that fails for you?

Gambit

Quote
"Fishface" <inva...@ddress.ok?> wrote in message

news:3e5042a0@newsgroups.borland.com...
Quote
> Well, I mean if it were completely handled by the component and
> not at the form level.  I tried DestroyWnd() and
> DestroyWindowHandle(), but aren't called unless the control is
> being recreated.  Hmm-- maybe something in WndProc()...

Re:Saving component properties from executable


Quote
Remy wrote:
> I doubt that, considering that the Lines property isn't freed until
> TCustomMemo::Destroy, which by law of both Pascal and C++
> languages, must execute AFTER your own destructor, not before it.

Hmm, nevertheless, I have text at runtime and my destructor looks like
this:

__fastcall TFFMemo::~TFFMemo()
{
 // Stuck a breakpoint here and s is empty.
 // String s = Lines->Text;
  // if(s.IsEmpty()) Beep();
  TFileStream *fs = new TFileStream("c:/testwrite.dat", fmCreate);
  fs->WriteComponent(this);
  delete fs;

Quote
}

I'm still using BCB5.  It works from a button click at the form level, though.
Maybe I'm overlooking something stupid-- I'm a little foggy today...

Re:Saving component properties from executable


Quote
"Fishface" <inva...@ddress.ok?> wrote in message

news:3e504a63@newsgroups.borland.com...

Quote
> Hmm, nevertheless, I have text at runtime and my destructor
> looks like this:

Your destructor is very dangerous.  You better wrap your code in a
try...catch, otherwise of the TFileStream fails, you're going to blow up
your class.  It's forbidden practice to allow exceptions to escape
destructors.

I tried it.  I derived a new component from TMemo, put it on a form, filled
in some text at runtime,and then close it.  Sure enough, only the Left, Top,
Width, and Height properties were saved to the output file, no text at all.

Gambit

Re:Saving component properties from executable


Hi, I did some web research and found a nice solution.
http://www.bridgespublishing.com/articles/issues/0203/Saving_and_load...
ponents.htm

The link above describes two utility functions SaveComponent and
LoadComponent that make use of TWriter, TReader, and TFileStream.

I call LoadComponent from the form's constructor and I call SaveComponent
from an overridden TForm::BeforeDestruction().  See below.

In the author's original source code (Damon Chandler)
http://www.bridgespublishing.com/articles/source/March02Code.zip, he makes
use of another function called RegisterOwnedComponents, which I find
unnecessary.

I tried to call the functions passing Form1 as the component, but it did not
work.  I think a container TPanel alClient-aligned, and containing all other
components would allow saving all properties excepting the form's position
and size..

Again, thanks for all responses -- Remy, you set me on the right track.

////////////////////////////////////////////////////////////////////////////
//////////////////////////////////
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
    //read in saved component state
   AnsiString cfgfilename = ExtractFilePath(Application->ExeName) +
ClassName() + ".cs";
   if (FileExists(cfgfilename)){
      LoadComponent(cfgfilename, MyComponent);
   }

Quote
}

void __fastcall TForm1::BeforeDestruction()
{
   TForm::BeforeDestruction();
 //save component state to file
   AnsiString cfgfilename = ExtractFilePath(Application->ExeName) +
ClassName() + ".cs";
   SaveComponent(cfgfilename, MyComponent);
Quote
}

Re:Saving component properties from executable


Quote
Remy wrote:
> Your destructor is very dangerous.  You better wrap your code in a
> try...catch, otherwise of the TFileStream fails, you're going to blow up
> your class.  It's forbidden practice to allow exceptions to escape
> destructors.

Yes, thank you.  I am just messing around, but I did have some problems
with that.  I found some good past discussion of this eventuality in language.cpp.
It seems that the VCL routinely throws exceptions to indicate failure.  I guess
that the Delphi guys aren't too keen on checking return values.

Quote
> I tried it.  I derived a new component from TMemo, put it on a form, filled
> in some text at runtime,and then close it.  Sure enough, only the Left, Top,
> Width, and Height properties were saved to the output file, no text at all.

Thanks for the confirmation.  The form level solution may be the acceptable,
but I was imagining a component which could save its state to a registry key
or configuration file specified at design time by published properties.  I was
also toying with the idea of a non-visual component which would save the
state of user chosen components at close to a specified registry key or file.
I thought the component might position itself to be the first destroyed by
manipulating its ComponentIndex.  The destruction of the component would
trigger the state saving.  Unfortunately, regardless of the ComponentIndex,
the ComponentCount is zero in the destructor, and in BeforeDestruction().
I see there are Delphi components which do this at www.torry.net/savers.htm
Going to examine this next:  http://www.drbob42.com/delphi4/d4constr.htm

Re:Saving component properties from executable


Quote
Fishface wrote:
> Going to examine this next:  http://www.drbob42.com/delphi4/d4constr.htm

He called them "events" which initially made me believe they were other than
the virtual BeforeDestruction() (and AfterConstruction()) I had already tried...

Re:Saving component properties from executable


Quote
Fishface wrote:
> Going to examine this next:  http://www.drbob42.com/delphi4/d4constr.htm

He called them "events" which initially made me believe they were other than
the virtual BeforeDestruction() (and AfterConstruction()) I had already tried...

I see Peter Below (Delphi Team B) once suggested subclassing the form and
detecting WM_CLOSE.  Should be an easier way, but I think he would have
known.  One line of code in OnFormClose may have to be acceptable.

Re:Saving component properties from executable


Quote
Fishface wrote:
> I see Peter Below (Delphi Team B) once suggested subclassing the form and
> detecting WM_CLOSE.  Should be an easier way, but I think he would have
> known.  One line of code in OnFormClose may have to be acceptable.

Ok, I got it.  The trick is to call the AddNotification() of the Owner and
override the virtual Notification().

__fastcall TFFMemo::TFFMemo(TComponent* Owner)
        : TMemo(Owner)
{
   if(Owner) Owner->FreeNotification(this);

Quote
}

// *************************

__fastcall TFFMemo::~TFFMemo()
{
 if(Owner) Owner->RemoveFreeNotification(this);

Quote
}

// *************************

void __fastcall TFFMemo::Notification(TComponent* AComponent,
                                                            TOperation Operation)
{
  TMemo::Notification(AComponent, Operation);
  if((AComponent == Owner) && (Operation == opRemove))
    {
       try
        {
          TFileStream *fs = new TFileStream("c:\\testwrite.dat", fmCreate);
          fs->WriteComponent(this);
          delete fs;
        }
       catch(Exception &) { }
    }

Quote
}

// *************************

void __fastcall TFFMemo::Loaded()
{
  TMemo::Loaded();
  if(!ComponentState.Contains(csDesigning))
    {
      if(FileExists("c:/testwrite.dat"))
       {
         try
          {
            if(FileExists("c:\\testwrite.dat"))
             {
              TFileStream *fs = new TFileStream("c:\\testwrite.dat", fmOpenRead);
              fs->ReadComponent(this);
              delete fs;
             }
          }
      catch(Exception &) { }
      }
    }

Quote
}

Go to page: [1] [2]

Other Threads