1
votes

I am looking at replacing an old custom form designer with Delphi's form designer. Our application used a custom program for generating forms that could be used our own report writer. It is difficult to maintain the old application and using Delphi for the form designer seems to be a good option. The application that uses this forms is also written in Delphi, but these forms will not actually be displayed as real forms, we will just iterate through the components and generate our report.

One of the features of the current form designer is a "neighbors list". The neighbors list keeps track of the next top, bottom, right, and left cell for every cell on the form. The old designer updates this list when the form is saved during the design phase.

Everything else I need to keep track of maps very easily to your typical control properties (position, height, width, etc.). I can't figure out how to generate and save this type of neighbor information in the dfm.

Is there any way for a component on a form, at design time, to get an event fired when anything on the form changes? Or an event when the form is saved?

I have thought about two approaches to the problem 1) Keep the neighbor information in each individual control. That will kind of work, but still has the problem of getting out of sync when other controls on the form are moved unless I can get an event that let's me know when to update.

2) Have a non-visual component that just keeps track of the list. I could add a custom property editor page that has and "update" button on it that would regenerate the list, but then I would need to remember to click that before the final version was saved. I can see that step being missed and would rather have something that just works.

I could also change the application to dynamically find the neighbors at runtime, but I was hoping I could find a way to make it work at design time.

A solution for any version of Delphi would work.

Any comments as to why this is a bad idea in general will also be appreciated as I have not convinced myself 100% that this is the right approach. :-)

2
It's difficult to say whether this is a good idea because you haven't given the rationale for having a neighbor list in the first place. Tell us why you need such a list, and then we can tell you whether it's a good idea to try to automate its upkeep.Rob Kennedy
corollary to Rob's question : Why not just stick with the current VCL Form support for tab-ordering and forget about neighbor lists?Warren P
The neighbor list is needed because I need more than just next and previous - I also need up, down, left and right. Currently the users can use the arrow keys to move around the form to enter data. We also have the "next" and "previous" concept mapped to the tab key. Think of a grid; each cell can have a top, bottom, left, and right but the tab key may take you to the top of the next column. The "good idea" question is really about using the Delphi Form Designer in general instead of trying to update the current custom build designer.Mark Elder

2 Answers

3
votes

Create a new TForm descendant and override the DefineProperties function to load and save the list as part of the streaming process. Marco Cantù covers the details for adding new design time forms in his Delphi Developer's Handbook, but you can probably get away with just calling RegisterCustomModule in your Register procedure.

Alternatively you could create a TApplicationEvents object (AppEvnts.pas), assign an OnMessage handler, and watch for any WM_SIZE messages. You can then use FindControl to get the TWinControl that the message is for and check to see if it's parented to your form. Make sure whatever filtering you do here is fast, since OnMessage will see every message for the entire IDE.

0
votes

Use the TComponent.Notification method. It's called on all components with a common owner when any of them is inserted or removed from its owner. You can call also call FreeNotification to get notifications about components with different owners.

For example, when the PopupMenu property is set on a button, the button calls the menu component's FreeNotification method. If the menu later gets deleted, it will call Notification on the button, and the button will clear its PopupMenu property since it no longer refers to a valid object.

You can override Notification to monitor insertions and deletions. A harder task will be to monitor when a component moves, if that's something you need to know. Just because a component was your left neighbor when it was added doesn't mean it will remain your left neighbor forever. (In fact, position probably isn't valid at insertion time anyway.) At run time, controls' positions are probably not going to change, so if you have a way of detecting relative positions of controls, the Loaded method is a good place to do it. That method is called after the DFM has been read and all the components' properties have been set.