What is the difference between Owner and Parent of a control? - delphi

I am bit curious about the two properties of a Delphi VCL control.
Each component has 2 properties as Owner and Parent at runtime. Can anyone help me to understand the difference between both? And how are they used by windows for displaying control or form?

Owner
Owner is a property introduced in TComponent, and Owner itself has type TComponent. The Owner is used primarily to manage the lifetime of designed components. That is, components that you place on the form designer (or indeed other design surfaces) and whose lifetime is managed entirely by the framework. The documentation says:
Indicates the component that is responsible for streaming and freeing this component.
When a form is created, the streaming framework parses the .dfm file and instantiates the components that are listed within. These components are typically created with Owner specified to be the form.
At the other end of a component's life is destruction. When a component is destroyed, it also destroys all of the components which it owns. Consider, for the sake of a concrete example, a TButton that sits on a TForm, placed there at design time. The streaming framework creates the button setting its Owner to be the form. The form, as a descendent of TComponent maintains a list of all the components that it owns. When the form is destroyed it walks over that list of owned components and destroys them. The button is destroyed in this manner.
There are many nuances to this:
Components don't need to be owned by the form. For instance, components created at run time are owned by whatever component you pass to the constructor.
Components need not have an owner, you can pass nil to the constructor. In this case, the programmer remains responsible for destroying the component.
Ownership can be changed during the lifetime of a component.
Because the streaming framework instantiates components, the constructor of TComponent is declared virtual:
constructor Create(AOwner: TComponent); virtual;
If you derived from a TComponent descendent, and you wish for that derived component to be placed on a design surface, then you must respect this virtual constructor. If you define a constructor in your TComponent descendent then it must override this virtual constructor.
It is worth pointing out that Win32 has a completely different concept of a window's owner, that should not be confused with the VCL concept of the same name. The Windows documentation says:
Owned Windows
An overlapped or pop-up window can be owned by another overlapped or
pop-up window. Being owned places several constraints on a window.
- An owned window is always above its owner in the z-order.
- The system automatically destroys an owned window when its owner is destroyed.
- An owned window is hidden when its owner is minimized.
Only an overlapped or pop-up window can be an owner window; a child
window cannot be an owner window.
In VCL terms, this concept is exposed by the PopupParent property. That property was introduced after Delphi 7 so will not be available to you. In Delphi 7, the framework sets the window owner, and gives no easy mechanism to override the framework's choice. If you do need to influence window ownership then you must override CreateParams and set Params.WndParent. Unfortunately, there are a number of problems with the VCL handling of ownership in Delphi 7 and it is sometimes necessary to grub around in these somewhat gory details.
To show how easy it is to get confused, the VCL documentation says:
WndParent: The window handle of the parent window. This is the same as the Handle property of the parent control.
This is simply wrong. For a top-level window, this is the owner rather than the parent.
Parent
Parent is a property defined in TControl and has type TWinControl. This property is used, broadly, to expose the Win32 concept of parent and child controls. The Windows documentation says:
A window can have a parent window. A window that has a parent is called a child window. The parent window provides the coordinate system used for positioning a child window. Having a parent window affects aspects of a window's appearance; for example, a child window is clipped so that no part of the child window can appear outside the borders of its parent window. A window that has no parent, or whose parent is the desktop window, is called a top-level window.
Essentially, the VCL Parent property maps directly onto the Win32 parent concept.
Note however, that Parent is defined in TControl. Now, TControl is not windowed, so a TControl is not a child control in the Win32 sense, because a Win32 window's children are themselves windows. So, a TControl with a defined Parent is a child in the VCL sense, known as a non-windowed child control. These non-windowed controls paint themselves as part of their parent's paint handlers. The canonical example of such a control is TLabel.
Note that when a windowed control, that is a TWinControl descendent, is destroyed, it also destroys all of its children.
A TWinControl descendent can enumerate its children using the ControlCount and Controls[] properties. These enumerate both windowed and non-windowed children.

Related

Delphi control MouseDown/Move/Up passed to underlying panel

I'm using Delphi 10.2.3. I have a descendent of a TCustomPanel for which I've overridden the MouseDown/MouseMove/MouseUp events to allow selection, dragging, custom painting, etc. Descendents of this panel will have various controls - TImage, TStaticText, TStringGrid, etc. - added dynamically at runtime, and some will have several such controls. The problem is that clicking anywhere in the panel that has some other child control in that location, that control gets the mouse events rather than the underlying panel.
Is there some way of having a control pass its mouse events to its parent, without having to dynamically assign OnMouseXxx handlers for every control added to the panel?
If a child is a TGraphicControl descendant, it does not have its own HWND in the OS, so for all practical purposes it doesn't exist to the OS. Thus, a click on the child will be sent to that child's immediate parent for processing. The VCL will then look for a child at the click coordinates, and if found then send the click to that child, otherwise handle it as a click on the parent. The methods involved in this lookup and delegation are not virtual or dynamic, so you can't override them, and they are invoked before the virtual Mouse(Down|Move|Up) methods are called on the determined target control.
If a child is a TWinControl descendant, it has its own HWND in the OS, thus a click on the child will be sent directly to that child for processing. The parent will not know the child has been clicked on, unless the parent has assigned appropriate event handlers to the child, or the child otherwise notifies the parent.
So, your TCustomPanel (which is a TWinControl descendant) can handle clicks transparently but only for non-windowed children, if it handles the WM_(L|M|R)BUTTON(DOWN|UP)/WM_MOUSEMOVE messages directly before passing them along to any inherited handler. That is not the case for windowed children. To intercept those messages, you would need to use a thread-specific mouse/message hook via the Win32 SetWindowsHookEx() function, looking for HWNDs that have your Panel's HWND as their (grand)parent.

Is there a way to implement a bottom-up event notification in Firemonkey?

I have a container control (TLayout or TPanel or TScrollbox, etc.) which can have several other nested controls inside. Is there a way in Firemonkey to know when the container becomes "active"? I mean for example:
when any of its children get focus or
user clicks any of its non-focus controls
I am asking for a kind of event-bubble. OnClick would be enough so when user clicks any nested control, the parent container is notified. Control's HitTest property would be a solution but if I set that property to False (to let the parent manages the onlick) on a TEdit, it becomes useless obviously (I can't type on it)
Edit:
A simple layout example:
Drop a TScrollBox in a form
Drop a TPanel in form and put it as child of the TScrollBox
Drop a TEdit in form an put it as child of TPanel
Ok, I can simply do a sort of Parent.Parent.Click after receive the OnClick on TEdit but imagine now several TScrollBoxes, with different level of nesting using TPanels with a bunch of different controls inside. It doesn't make sense neither adding the onclick code for each control in the tree, nor change the hierarchy of Parent.Parent.Click every time I redesign the layout adding an intermediate parent control.
Is there any way to do this in Firemonkey (either for Windows or MacOS)?
PS: I'm using Delphi 10.2.3 (Tokyo)

(delphi) how to add property to child controls?

In the Delphi IDE, some components in Delphi have the ability to "add" properties to the child controls they contain in the property editor.
How can I achieve the same thing with my own TCustomPanel descendant?
Some more details:
What I want to achieve is the following: I have a very complex configuration dialog for an application with a large number of visual components.
I want to add to each of these components a "complexity index" (an integer) that will be used to show or hide the component based on a selection made by the user (a dropdown with "simple", "advanced" and "expert" options).
I understand that the property will actually belong to the parent panel but I need a way to display it, in the IDE, as if it was attached to the control it is related to.
The perfect exemples are the various "organizational" panels provided by Delphi: TGridPanel and TRelativePanel. Each of these have a ControlCollection (published) properties that is used to hold the actual states of the additional properties but I failed to locate how the property editor knows that it must attach the properties to the child controls.
Here is a screenshot of a TLabel placed inside a TRelativePanel with the relevant properties highlighted:

Firemonkey and dockable forms

Is it possible to have dockable forms in FireMonkey, as I have inspected the forms properties, and there is no such property to do that.
Is there any workaround to accomplish that?
There's nothing built in, as far as I know but it shouldn't be too difficult to add in yourself. Just bear in mind that any form can parent any control on another form:
On the child form, add any controls inside a container (e.g. a TLayout).
Create the child form.
Set the Parent property of the TLayout (etc.) to the parent form (or, more probably a container on the parent form so you can set the child TLayout's alignment to alClient).
If you want to show the placement during a drag operation, experiment with the various effec ts included.
Unlike VCL, the Firemonkey does not have a built-in dockable interface for creating dock forms. But there is a commercial component for creating a complete dockable interface in FMX. The component implements dockable forms only. So far, the docked document panels are not supported (like the visual studio IDE does) and no docked toolbars. But in general, they have all the necessary functionality, including auto-hide panels and the ability to be saved/restored in/from XML.
https://www.devmachines.com/firedocking-overview.html

Making an editable designtime component for Delphi

I've been searching the whole internet for an answer but I cant find one.
What I want to do is to create a component that I, in design time, can add components to, move them around, right click on them to pop up a menu, change their properties, etc etc.
Like, for instance, I drop my component "A" (which is based on TImage32 from the Graphics32 library), and then I want to be able to drop a component "B" (which is based on TBitmap32) in to A, but since B is not inherited from a standard VCL like TPanel I dont know how to make a design time component.
What you are searching for is the ability to create a parent/child relationship. The parent acts as a container and the child is contained within the bounds of the container. A TPanel is a classic example of a container. Any visual component can be a child.
In terms of ancestry the parent must be derived from TWinControl and the child must be derived from TControl. In practice you seldom derive from these classes directly, rather from one of their descendents. The other factor, if I recall correctly, is that the parent control must include csAcceptsControls in its ControlStyle.
Now, TImage32 does indeed derive from TWinControl and so it can act as a container. However, I am not sure whether or not csAcceptsControls is included in the ControlStyle for TImage32.
I'm really not familiar with TImage32 and don't know whether or not it can act as a parent. I have a suspicion that it is not designed to act as a container. If that is the case then you can add csAcceptsControls to the ControlStyle in the constructor of your derived class and have the control act as a parent.
I suspect that if TImage32 does not include csAcceptsControls then this is by design and the image control is not expected to act as a parent.
Apparently TImage32, unlike the VCL TImage, is indeed capable of acting as a parent to other controls.
As for the other control in your question, TBitmap32 is not derived from TControl and cannot be a child control.

Resources