View Issue Details

IDProjectCategoryView StatusLast Update
0001421JEDI VCL00 JVCL Componentspublic2004-03-28 06:27
ReporteranonymousAssigned Tojfudickar 
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionno change required 
Product Version 
Target VersionFixed in Version 
Summary0001421: TJvAppIniStorage losing stored properties
Description 
When you use more than one main form,
TJvAppIniStorage will reset all stored properties back to
the inherited vaules on the sub forms when the sub
forms are .free from the main form.

This was tried with no luck:
FrmSub.JvAppIniFileStorage2.Flush;
FrmSub.JvAppIniFileStorage2.Reload;

(The resulting ini file was good at this point)

But after FrmSub.Free all properties in the ini file were
reset again.

There is also a JvAppIniFileStorage1 on the main form.

The above issue was posted by more than one person
on the jedi.vcl newsgroup.
TagsNo tags attached.

Activities

2004-03-04 16:36

 

JVtesting.zip (362,975 bytes)

craigism

2004-03-04 16:38

reporter   ~0003208

The properties for the second form are cleared by this code in the create event of the main form:
procedure TForm1.FormCreate(Sender: TObject);
begin
  if FormSub = nil then
     FormSub := TFormSub.Create(self);
  // This should cause the problem
  // I check some settings here...
  // FormSub.JvAppIniFileStorage1.Reload; << does not help
  FormSub.free; //<< resets the properties.
  FormSub := nil;
end;

2004-03-04 17:23

 

JVtestingChanged.zip (368,969 bytes)

jfudickar

2004-03-04 17:23

developer   ~0003210

I have updated your example. There is no problem for me now.

Some hints:
- Use one global JvAppStorageComponent
- The TForm1.FormCreate is useless (for me)
- It works now with Registry and Ini-File

jfudickar

2004-03-04 17:25

developer   ~0003211

Please check my sample and give a feedback if the bug can be closed.

Greetings and thanks.
Jens

anonymous

2004-03-04 18:56

viewer   ~0003212

First I want to thank Craig for following up on my bug post while I was sleeping and then at work all day... I owe you one!

Jens,

I may have had two problems with my implementation. I found I had a stray JvAppIniFileStorage on my main form in addition to the instances I had on the two separate sub forms. Also, I hadn't set the AppStoragePath for either of the JvFormStorage components on the subforms.

Once I removed the JvAppIniFileStorage on my main form and set the AppStoragePath, everything work correctly for me. I dynamically create one or the other subform (only one will exist at any one time), so I guess I won't have the same problem that Craig exhibited in his example.

Specifically, the usage is that one instance of JvAppIniFileStorage should exist at any one time. Somehow, that requirement is less than desirable, but I can't think of a elegant solution, so I can certainly live with that restriction!

Thanks to both of you for helping me through my problem. If Craig is okay with the solution, you can close the case as far as I'm concerned.

-Charles

jfudickar

2004-03-04 23:56

developer   ~0003215

As i said before, i think the best solution is to work with one central JvAppStorage. The point is that the AppIniStorage cashes the contents. So if you work with differnt Storages, there can be a problem.
Greetings
Jens

marcelb

2004-03-05 01:13

manager   ~0003216

Jens, I agree. A central storage component is practically the only way that will work, regardless of which back end is used. Personally, if you have many forms, I would put the storage component on a data module that will be used by all forms.

This is definately not a bug, just a feature (possibly annoying for some, but, well, though <g>)

craigism

2004-03-05 05:04

reporter   ~0003220

Last edited: 2004-03-05 06:19

Jens,
In your example zip file the sub form still loses its stored property values if you do not .show or .showmodal the sub form. Use your example to add text to the fields in the sub form then exit the app. Next, run the app's main form only, then exit and you will see that the ini and the sub form has reset its stored values back to the inherited vaules. Even a data module as marcelb reccomemds will still have the stored values lost.
(FIY I did delete the unused registry component, JvAppRegistryStorage1 before testing the ini functionality)
-Craig

edited on: 03-05-04 06:19

cginzel

2004-03-05 06:29

reporter   ~0003224

Okay, I though about it overnight... If you intend for TJvAppIniFileStorage to be an "application" store, then why not move the declaration of FIniFile from the class to the package implementation so it is treated as a "class" variable? Then add a usage counter to keep track of when you really need to deallocate it...

implementation

uses
  JvTypes, JvResources;

var
  IniFile: TMemIniFile;
  UsageCount: integer = 0;


constructor TJvCustomAppIniStorage.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  IniFile := TMemIniFile.Create(Name);
  inc(UsageCount);
end;

destructor TJvCustomAppIniStorage.Destroy;
begin
  inherited Destroy;
  // Has to be done AFTER inherited, see comment in
  // TJvCustomAppMemoryFileStorage
  dec(UsageCount);
  if UsageCount = 0 then IniFile.Free;
end;

This way it work philosophically like you guys intended and it will not suffer from errant use by the uninitiated like me! This way each placement of a TJvAppIniFileStorage component becomes a local reference to the "application" store.

-Charles

Just my $.2

jfudickar

2004-03-06 08:22

developer   ~0003243

But this will not help in all ways.

It's a little bit more complex. Some issues:
1. Multi Threading
2. The logic must be more complex because different AppStorageComponents can use different files.
3. Don't know, maybe there are better solutions.

Any comments
Greetings
Jens

marcelb

2004-03-06 09:07

manager   ~0003244

Craig: it reverts to the defaults because of the way FormStorage works: values are read from the store when the form is shown and written when it is destroyed. I think the Loaded method of the FormStorage component should resotre the values/placement/sizes instead of (or in addition to) the FormShow event (and in general the way it hijacks the events of the form is bad practice that should be erradicated anyway)

Charles: Jens is right; too much trouble and generally not worth to go that route.

jfudickar

2004-03-06 09:21

developer   ~0003245

Hi Craig,

the problem is raised by your project definition.

Both forms are in the project initialisation. Removing the subform of the project intialisation solves the problem.

Without looking into it seems to be, that the FormStorage Component loads the values when the form is shown the first time, and stores it when deleting.

I must look into it.

Greetings
Jens

2004-03-06 10:17

 

JVtesting.zip (363,611 bytes)

craigism

2004-03-06 10:23

reporter   ~0003246

Last edited: 2004-03-07 08:00

"Removing the subform of the project intialisation solves the problem"
did not solve the issue so, here is my work around:
(Zip file uploaded)
procedure TForm1.Button1Click(Sender: TObject);
begin
  if FormSub = nil then
     FormSub := TFormSub.Create(self);
  FormSub.showmodal;
  FormSub.free;
  FormSub := nil;
  JvAppIniFileStorage1.Reload; << after the sub form writes to the ini file
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  if FormSub = nil then
     FormSub := TFormSub.Create(self);
  FormSub.Visible := false;
  FormSub.Show; << short flicker until the .free is called
  // I use the stored values here...
  FormSub.free;
  FormSub := nil;
  JvAppIniFileStorage1.Reload; << after the sub form wrote the ini file.
end;

It is an extra step but it works great (except for the flicker). Thank you all for helping me get through this. I'm ok with closing this issue now.

- Craig

edited on: 03-06-04 10:23

edited on: 03-07-04 08:00

2004-03-06 11:03

 

JVtestingworking.zip (369,514 bytes)

jfudickar

2004-03-06 11:05

developer   ~0003248

Craig,

look at my example.

I can't see any further problems.

Please try it again.

Jens

craigism

2004-03-06 19:12

reporter   ~0003250

Last edited: 2004-03-07 09:33

Problem solved, see the next post for use of '.RestoreFormPlacement'. I'm editing out my comments below do to the better solution found.

Jens,
Your last posted zip file will not give me access the the sub form's values so I can use them as application settings like data path info.
.
.
.

-Craig

edited on: 03-07-04 09:33

craigism

2004-03-07 08:55

reporter   ~0003251

Last edited: 2004-03-07 09:29

I tried this.

procedure TForm1.FormCreate(Sender: TObject);
begin
  if FormSub = nil then
     FormSub := TFormSub.Create(self);
  FormSub.JvFormStorage1.RestoreFormPlacement; << working fine
// FormSub.Visible := false; << no longer needed so no flicker
// FormSub.Show;
  // I use the stored values here...
  FormSub.free;
  FormSub := nil;
  JvAppIniFileStorage1.Reload;
end;

-Craig

edited on: 03-07-04 09:29

craigism

2004-03-07 16:58

reporter   ~0003257

Last edited: 2004-03-07 17:21

Help! I just updated JVCL. Now none of the TJvCustomAppIniStorage stuff is working at all. I noticed that JvAppStorage.pas was updated on the 6th. Did this break using an ini file? TJvAppRegistryStorage still works. I went back to the prior one 1.18 (or 1.19) of JvAppStorage.pas and ini works again.

-Craig

edited on: 03-07-04 17:21

user72

2004-03-08 01:25

  ~0003258

You can see what's changed here:
http://cvs.jvcl.sourceforge.net/viewcvs.py/jvcl/dev/JVCL3/run/JvAppStorage.pas

marcelb

2004-03-08 03:21

manager   ~0003261

Craig, it appears the change Jens has done introduced a new bug. AFAICT, if the Location property is not set (either because of loading from the DFM or through code), the storage is deemed uninitialized, resulting in no file being used. Luckily for us, Jens has coded in such a bad way (<g>) we can just explicitly set Location to it's current value (i.e. using <Store>.Location := <Store>.Location) and it all works. I don't quite understand why he did that though. To me, it seems totally obsolete.

jfudickar

2004-03-09 14:55

developer   ~0003290

Hi Everybody.

Sorry for that. I have tested everything, but not the case that the Location was flExeFile.

I didn't think that my changes were so bad (<g>). They made sense (for me) but they were not perfect.

What i wanted to prevent was that the reload procedure was called before all properties were set.

Now i changed it via an overloaded "loaded" procedure. It seems to work for all cases, hope so.

I found the problem testing the new flTemp type. If this property is set, the component tries first to load the Ini-File in the exe-directory and after that the component in the temp-directory. So reload was called twice. I didn't want that.

Please give it a new try.

Greetings
Jens

marcelb

2004-03-10 07:00

manager   ~0003301

Jens,

How could Reload be called before the component is loaded? FormStorage doesn't do anything unless the form is shown and I'm pretty sure that when the form can be shown it is done loading that form and any form/data module/component it depends on. Unless you are abusing the FormCreate event (although I think that one is also called after it is loaded).

The "bad code" was referring to the fact that the Initialized (or whatever it was called) was set, regardless if the value of Location actually changed. Usually that's not a good thing, although there are situations where it can be very helpful.

Anyway, I haven't checked your changes, but I'm sure you got it covered now ;-)

jfudickar

2004-03-10 07:14

developer   ~0003302

Hi Marcel,

the point of reload calling is the following:
In the procedure Loaded the properties "Location" and "Filename" where initialized. Both call a "Set"-Procedure and this procedure calls the reload procedure.

The initiating problem was: I had changed the location to flTemp. The ini-file doesn't exist in the temp directory, it exists in the exe-directory.

While the "Loaded" procedure the filename-property is set first. Then the file is loaded. Then the Location-property is set. Now the reload is executed again. But now the file does not exists (because Location now =flTemp). So the file is not loaded and the contents of the old file still be loaded
And there we have an other bug, i've not fixed until now (coming to me this night).
The reload checks if the file exists and then loads the file. If the file does not exist, nothing happens. That had to be changed. In the case that the file does not exists, the old contents had to be changed.

I hope now it's clear.

Greetings
Jens

craigism

2004-03-10 09:10

reporter   ~0003303

Will I still have to do this with the new changes?

procedure TForm1.FormCreate(Sender: TObject);
begin
  if FormSub = nil then
     FormSub := TFormSub.Create(self);
  FormSub.JvFormStorage1.RestoreFormPlacement; << reads sub form's settings
  // I use the stored values here for path and other application settings.
  FormSub.free; << writes sub form settings
  FormSub := nil;
  JvAppIniFileStorage1.Reload; << fills the buffer with both the main form and sub forms settings.
end;

Thank You again,

-Craig

jfudickar

2004-03-10 23:48

developer   ~0003307

Hi Craig,

i think so yes. The changes i had done were only for the problem of changing the Location-Property at designtime. They didn't change anything else.

Greetings
Jens

Issue History

Date Modified Username Field Change
2004-03-04 05:51 anonymous New Issue
2004-03-04 16:36 craigism File Added: JVtesting.zip
2004-03-04 16:38 craigism Note Added: 0003208
2004-03-04 17:20 jfudickar Status new => assigned
2004-03-04 17:20 jfudickar Assigned To => jfudickar
2004-03-04 17:23 jfudickar File Added: JVtestingChanged.zip
2004-03-04 17:23 jfudickar Note Added: 0003210
2004-03-04 17:25 jfudickar Note Added: 0003211
2004-03-04 17:25 jfudickar Status assigned => feedback
2004-03-04 17:25 jfudickar Resolution open => no change required
2004-03-04 18:56 anonymous Note Added: 0003212
2004-03-04 23:56 jfudickar Note Added: 0003215
2004-03-05 01:13 marcelb Note Added: 0003216
2004-03-05 05:04 craigism Note Added: 0003220
2004-03-05 06:19 craigism Note Edited: 0003220
2004-03-05 06:29 cginzel Note Added: 0003224
2004-03-06 08:22 jfudickar Note Added: 0003243
2004-03-06 09:07 marcelb Note Added: 0003244
2004-03-06 09:21 jfudickar Note Added: 0003245
2004-03-06 10:17 anonymous File Added: JVtesting.zip
2004-03-06 10:23 craigism Note Added: 0003246
2004-03-06 10:23 craigism Note Edited: 0003246
2004-03-06 11:03 jfudickar File Added: JVtestingworking.zip
2004-03-06 11:05 jfudickar Note Added: 0003248
2004-03-06 19:12 craigism Note Added: 0003250
2004-03-07 07:58 craigism Note Edited: 0003250
2004-03-07 08:00 craigism Note Edited: 0003246
2004-03-07 08:55 craigism Note Added: 0003251
2004-03-07 09:29 craigism Note Edited: 0003251
2004-03-07 09:33 craigism Note Edited: 0003250
2004-03-07 16:58 craigism Note Added: 0003257
2004-03-07 17:01 craigism Note Edited: 0003257
2004-03-07 17:21 craigism Note Edited: 0003257
2004-03-08 01:25 user72 Note Added: 0003258
2004-03-08 03:21 marcelb Note Added: 0003261
2004-03-09 14:55 jfudickar Note Added: 0003290
2004-03-10 07:00 marcelb Note Added: 0003301
2004-03-10 07:14 jfudickar Note Added: 0003302
2004-03-10 09:10 craigism Note Added: 0003303
2004-03-10 23:48 jfudickar Note Added: 0003307
2004-03-28 06:27 jfudickar Status feedback => closed