3
votes

We have a large legacy database driven VCL application which consists of over 300 different forms. We would like to provide a practice (dummy) database along with our software which is installed alongside their production database - with the ability to switch in-between them (for training / practice, etc.).

The problem is that when users are using the practice mode, we have to make something very clear to stand out to them so they know they're working in the practice mode. The most ideal solution would be to put a red border around the inside edge of every single form. But there are so many forms that I don't want to modify each and every one of them.

How can I add such a frame (inside the Windows border, not outside) along the edge of every form across the application from one global place?

I cannot use VCL styles, otherwise I would implement it from there. I'm looking for something on a global level which can possibly iterate every form and draw this border. But that also means catching every form's resize messages and re-drawing this border.

The easiest way I can see is to create a base form which has this functionality, and inherit every form across the system from this base form. But this still means making sure every form is based off of this. We've had other issues in the past modifying existing forms' base forms (another subject), so I'd like to avoid that solution, if there's another easier solution.

3
Your forms are not based on an own base class?bummi
If I were designing this system from the ground up I would definitely make a base form. Problem is, software's about 20 years old and is huge. Many different forms already inherit many times over.Jerry Dodge
So insert a base form. What's stopping you?David Heffernan
@DavidHeffernan Because that still means modifying every form across the system, which we've already experienced issues attempting (for something else in the past, not this subject). I'm hoping there's a way to do this without touching every form's code.Jerry Dodge
Couldn't you catch the TScreen.OnActiveFormChange event and use that to dynamically add some kind of internal border-like component?MartynA

3 Answers

4
votes

You need to insert a base class in there. TMyBorderForm inherits from TForm, and it has the border behavior. Then make all of your forms inherit from TMyBorderForm, instead of directly from TForm.

4
votes

There are ways to hook into the form streaming system, for example by overriding TComponent.ReadState for your form to add an event handler to the TReader handling your streaming, but they require you to actually change code in the form class in question. There doesn't appear to be any way to globally modify TReader behavior throughout the program. So without an actual base form class for all the forms in your app, there's no easy way to do this.

Even trying to patch TComponent.ReadState in-memory would be very difficult to do right, because it's a virtual method and there's no override for TCustomForm, so any change you made could affect all components and not just forms.

Honestly, the best way to handle this is probably just to bite the bullet and run a global search over your codebase for class(TForm and change them all to be a subclass of some custom form class that exhibits the behavior you're looking for. There are probably theoretically other ways to accomplish it, but they would require some very hairy runtime tricks that could have unpredictable side-effects.

0
votes

There is a variation on Chris' answer, assuming you have your DFMs stored as text.

  1. Define a form that your forms all inherit from.
  2. You load all your PAS files in a text editor and replace the Class(TForm) with class(TMyBaseForm)
  3. IIRC you also have to edit all your DFM files - there's a string 'object' to change into 'inherited'. Try this first with a test app, because I'm writing this based on what I did in the past, and I'm not sure this answer is 100% complete.
  4. You add the border functionality (on/off) to TMyBaseForm

Strictly speaking, this requires you to 'go through all the forms', but 'Open selected files' and 'Replace in all open files' is not really a big deal ;-)

The only drawback is if you do not yet have your DFMs stored as text, you'll have to change that first.

[Inheriting from your own 'base form' is often a good thing for large projects. We use that e.g. for third party components that do not have the default properties we want - if the developers forget to change the default property, the run-time code in the base form will update it].