views:

58

answers:

2

I am just wondering if I'm doign something that might be bad, although it seems a very practical solution to me...

I have two forms which the user will have to walk through. The user clicks on a button and form1 pops up. The user presses OK and the second one pops up. The user click OK again and the screens are gone. Or the user clicks on Retry and the screen goes back to the first one. The two screens are completely different sizes with different information.

So I came up with this code:

  Form1 := TForm1.Create(SharedData);
  Form2 := TForm2.Create(SharedData);
  repeat
    ModalResult := Form1.ShowModal;
    if (ModalResult = mrOK) then ModalResult := Form2.ShowModal;
  until (ModalResult <> mrRetry);
  Form1.Release;
  Form2.Release;

I've tested this code and it seems to work like a charm. In this code, SharedData is an object that contains data that's manipulated by both forms. I create this object before the two forms are created and when ModalResult==mrOK I just write the data back to the database.

Problem is, while I think this is a clean solution to handle flipping between two forms, I can't remember ever seeing something like this construction before. Of course, I'm a Genius. (At least, me Ego tells me I am.) But would there be something against using this piece of code or is it just fine?

+3  A: 

If the code does what it's supposed to, I think it's fine. I've not seen anything quite like it before either, but it's pretty obvious what it's doing... which in my book is far better than just blindly following other people's work. :-)

Richard J Foster
Basically, that's what's bothering me the most. The code looks so simple while most seem to use far more complex techniques. :-)
Workshop Alex
+1  A: 

I don't see anything wrong with the code. I do question, however, the passing of SharedData to the constructor of both forms. Unless you've overridden the constructor (using reintroduce as well), the argument to TForm.Create() accepts an owner; that owner is responsible for freeing the objects it owns. Since you're freeing them yourself, there's no need to assign an owner; just pass nil to the call to Create() to avoid the overhead of saving the reference, accessing the list of owned objects when one is freed to remove the reference, etc.

Also, Release is designed to be called from within the event handler of the control itself, such as in a button click event. It makes sure that all pending messages are handled before the control is actually freed, in order to avoid AVs. Using it the way you are again adds unnecessary overhead, as you're not using them inside an event handler. You can safely just use Form1.Free; instead.

To clarify use of Release, it's for use in code of the Form itself. For instance, if you have a button on the form, and you want that button's click to cause the form to be freed, you use Release:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Self.Release;
  Close;
end;

This allows the button click to free the form, but makes sure that the subsequent call to Close runs first. If you use Free instead of Release above, you could end up calling Close on a non-existent Form1. (Chances are it would still be OK, because of the silliness of the code above; the form would still be resident in memory. Still a bad idea, though.)

Ken White
SharedData is of type TComponent. Within the forms, it can be typecasted again to the proper TSharedData class.
Workshop Alex
I tend to always use Release as a good coding practice. Others sometimes maintain my code and I don't want them to make a mistake when they copy the Close() command inside an event. The use of Release also delays the free action until the messageloop gets active again, after all previous messages. Thus, if these forms did send a few messages after returning ModalResult, (like timers) those messages would still be processed first.
Workshop Alex