views:

735

answers:

3

Before Delphi 2006 (I think) introduced the TFlowPanel and TGridPanel, I did a control that was similar in concept. It still does a couple of things those controls do not do, and when upgrading my code to Delphi 2009, I decided to add a couple of enhancements to that as well.

Right now, the order of the child controls is determined by their creation order. The FlowPanel and GridPanel show a better way with ControlIndex and other filtered properties, but I was wondering if there is a way to handle drag and drop reordering in design-time? As far as I can tell, dragging an edit control and dropping it onto my panel doesn't call anything that I can access at design-time.

I was half-fantasising about a way to either detect the drop operation directly, or to perhaps detect when a control is moved so I can determine where it should go.

Any ideas?

Update: OK, got it working. The container control was already overriding AlignControls to manage the placement of the controls. When you drag the nested control and drop it, AlignControls is again called. I then compared the new coordinates of the control with the other controls in the list and moved it to the appropriate position.

There were a couple of problems that I had to work through (mostly related to the many calls to AlignControls) but the basic concept is simple enough. Thanks to all the commenters for all the help.

A: 

Have you tried to write an "OnDragDrop" event for your grid component, where you check if your component is in design mode?

I haven't written such a component yet, but I don't see why the event shouldn't trigger.

LeGEC
Hi LeGEC.I didn't try OnDragDrop yet, but it seemed like all the other mouse events are intercepted by the form designer, so you never get notification that a control is being dragged.
Cobus Kruger
+2  A: 

You can't drag a control that's already on the form and drop it onto your panel. Dragging is only for moving a control, not for changing its parent. To change the parent, cut and paste.

If the control is already on your panel, and you want to move it to another position on your panel, then the panel can control the layout by overriding the TWinControl.AlignControls method. When a control is moved, its SetBounds method is called, and among the things tha happens is that it calls AlignControl(Self) on its parent window. That calls AlignControls. Look in Controls.pas, and you'll see that that's a complicated method, but it's what is responsible for the layout of the children on a control, and that's exactly what you're planning to change.

Rob Kennedy
Hi Rob,I think I wasn't too clear about my intentions re controls that get dropped on my container - see my response to John's comment.With regards to using AlignControls to handle the reordering, you're right of course. I'm using AlignControls already to arrange the children but right now I completely ignore the left and top properties. My concern is that taking those into account will make it fairly difficult to determine when a control is just added and when the user is attempting to reorder.I'll give it a go though and report back.
Cobus Kruger
+1  A: 

Perhaps some of these suggestions might help.

You can re-parent a control in the designer without having to do cut-and-paste. View the structure pane, and simply drag the visual control to the node of another parent in the structure pane. If you have things in a flowpanel, drag everything out of the flow panel and drag them back in the order that you want them to be.

(You can re-parent ANY visual control this way, without changing anything other than its parent. I highly recommend doing it this way.)

You can view the form as text, and move the declaration order around in there -- but obviously you'll need to be careful when editing the "resource" file directly.

You can set tab order in the designer, so you could make a different control based on tab order that works as you want. You can right click on the form and change the creation order of the non-visual controls, but that doesn't work with visual controls.

John Kaster
Thanks, John. My question really related to being able to support it from within a custom control - basically for the control to determine that another control was being dropped on a position that forms part of my control's bounding rectangle, so that its parent can be changed.I had some second thoughts about this though - aside from not knowing where exactly to start, it will make the control act differently from other containers which may be confusing to some users of the control.
Cobus Kruger
You may want to make it a component editor instead, then - pop up your own UI from a right mouse click, and use either the old-fashioned move up/down or implement the drag and drop on that control.
John Kaster