Delphi - move control to the ancestor form - delphi

I have more than 50 forms which have the same button on them. All of them are derived from the same ancestor. Is there any automatically way to move that button(or any other control) to the common ancestor?

David Miro had the right answer, but I think he misunderstood what you want to do. You are not trying to move the position of the butttons.
If you have not edited the buttons on the child form(s), you can add a new button on the parent. It will appear automatically on each child form. It will be a new button, which must have a different name but there will be an inherited button on each form. Then you will want to edit each child form to remove the original button. You will have a button and it will be inherited. If the event handler is always the same, you can code that into the parent as well.
If you have edited the buttons on the child forms previously, you can do this. The only way I know is to edit the DFM file of the form. A button declared in the form is defined without any reference to a parent. An inherited button is defined with an INHERIT in front of it. You need to add the INHERIT word, which tells the form that the button is inherited. If that sounds complicated, just create 2 buttons and look at the difference. It's not really too complicated.
The difficulty is this: you can't inherit from something before you create it (the parent button). And, you may have some difficulty creating the parent because the children already have a component with that name. You can change the name if you have to. But this can be done. I think this is what you are looking for. Strange there's no easier way to do this, because improvements like this are often created in the child form first.

At design time no problem. If you move parent button position , automatically moves the children buttons. But if you moved the child button, then this no longer works.
A solution. Although tedious, is to edit the form dfm child file and remove the attributes you need to inherit from dfm parent file (button.left, button.right, etc. ..)
With this procedure get it working again

Related

Selection contains a component introduced in an ancestor

Is it possible delete or add new component inside free embracadero theme?
What is ancestor?
Ancestor, in this context, means a class in the chain of classes from wich the object under discussion inherits. For example look at TButton in help. At the top of the help page, all ancestors of TButton are shown as a chain of classes starting with TObject
Thus, the error message means that an ancestor class (ancestor of your selection) has declared the component you try to delete.
If your version of Delphi comes with style files, you may modify them. I would copy the original style file to a safe place.
Note, that the structure view, left top of IDE, shows a different hierarchy that shouldn't be mixed with the class hierarchy. The parent - child chain (structure) indicates the components that hosts other components. E.g. A form can be a parent to a panel which might be the parent of a button. Or a grid panel that has collections of other components.
I found that if you change the View: drop-down menu to Master you can delete the selected component(s).
You have to switch to the Master View in order to delete components you dropped on the form.
Go to View: Master
You have to switch to the Master View

How can un-embed a subform from another form?

I'd like to swap the subforms that appear in a container on my main form.
I've found a method of assigning one form as a subform of another here by making it's parent a container on the main form.
procedure TParentForm.EmbeddForm(AParent:TControl; AForm:TCustomForm);
begin
while AForm.ChildrenCount>0 do
AForm.Children[0].Parent:=AParent;
end;
This works pretty much as I expected it to for adding a subform; however, I can't seem to replace it once it's already been made a subform.
niling the parent for the subform doesn't seem to do the trick, nor does setting its parent to it self.
Is there a way to un-embed this subform from its container?
I'd rather not destroy an recreate these subforms all the time, just swap them out.
In Firemonkey, to embed a form, you should first encapsulate all your controls on a TLayout of some sort. Then, you can assign the parent of that layout to whatever container you need.
MyLayout.Parent := MyContainerInAnotherForm;
This way, you only have one variable (of the layout) to reference the entire "form". Bear in mind that FMX is widely based around layouts.
When you want to re-assign the original form, just assign that layout's parent back to its original container.
MyLayout.Parent := MyOriginalContainerForm;

form main + form child stacking issue

I am using main form and child forms.
If I open 2nd child form with
TMYForm.Create(nil);
It does not stack it on the 1st child form top.
Is there any way for 2nd and X'th child form to appear in exact same position as 1st child form?
Or I need to destroy old child form while creating new one (as stacking is done automatically)?
That is the expected behavior. Without specifying otherwise, Forms will open on the right and down from the position of the previously opened.
If you want to control the position of your form, change its Position property to poDesigned, but you have to set its Top and Left properties to ensure it'll be visible.
Or you can used some presets: poDesktopCenter, poMainFormCenter, poOwnerFormCenter or poScreenCenter.
Try putting this:
TMYForm.Position:=poMainFormCenter;
or
TMYForm.Position:=poOwnerFormCenter;
Before TMYForm.Create(nil);
-S
If you have references to the child forms, use Form2.BoundsRect := Form1.BoundsRect

Delphi - Duplicate tpanel and tbuttons on second form

On my main form I have a TPanel containing buttons that act as a toolbar. I want to clone/copy this toolbar and the buttons and their functionality to a second form.
Cloning the menu was simple using newmenu.merge(mainmenu). That was an excellent shortcut to duplicating a Tmainmenu.
But I am at a loss on how to easily duplicate my toolbar without having to manually assign the events and keep a timer to compare and track which buttons are enabled and disabled in comparison to the real mainmenu on the main form. Depending on what the application is doing the main toolbar buttons will be enabled and disabled at various times.
Any ideas here? Thanks for any suggestions or tips to make this easier.
Duplicating the controls
In the Form Designer, select the panel and press Ctrl+C to copy it and all its children to the clipboard. Go to the second form and press Ctrl+V to paste.
If you're still working on the design and want to keep it consistent between both forms, then create a TFrame and design your toolbar layout there. Then put an instance of that frame on both your forms. Changes to the frame design will be reflected in the forms.
See Working with frames in the help.
Making sure both sets of buttons are enabled consistently
Create a data module. Put a TActionList on it. Add an action to it for each button on your main form. Assign event handlers to the actions' OnUpdate events. In them, set the actions' Enabled properties. Finally, assign each button's Action property to refer to the corresponding action object. The buttons will automatically get enabled and disabled with the actions. No timer required.
Furthermore, you can handle the actions' OnExecute events, too. Clear each button's OnClick property, and then move the button's OnClick code into the corresponding action's OnExecute handler. It will automatically get called when you click the button, even though the OnClick property is empty.
When you assign the Caption or Hint property of a TAction, the corresponding properties of any associated controls also change. Likewise for images, if the control supports them. Actions can be assigned to menu items, too.
See Using action lists in the help.
Acting like a toolbar
Just use TToolbar. That's what it's for.
Or, once you're used to actions, put a TActionManager in your project and use it with TActionToolbar and TActionMainMenuBar. See Organizing actions for toolbars and menus in the help.
Are the buttons attached to actions? If so, you can use the OnUpdate event of the TActionList to specify what should and should not be enabled. If not, it isn't too much work to convert to using actions.
If you go this route to convert to using a ActionList, consider putting the ActionList in a datamodule where different units and forms could reference it.
You can Use ClipBoard Object For Copy Your Panel.
Clipboard.SetComponent(Panel1);
Clipboard.GetComponent(Form2,GroupBox1);

Design-time drag and drop in Delphi?

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.
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.
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.
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.

Resources