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.
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.
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.
There is a variation on Chris' answer, assuming you have your DFMs stored as text.
- Define a form that your forms all inherit from.
- You load all your PAS files in a text editor and replace the Class(TForm) with class(TMyBaseForm)
- 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.
- 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].