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.
Related
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)
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.
I have a project where I try to share form files between Delphi and Lazarus. This actually works well excep with GroupBox there "top" values is caluculated against two different "tops". This menas that in Lazarus the controls are moved about 20-30 pixels too far down the TGroupBox.
Anyhow, assuming I design in Delphi, and I make a descendant TGroupBox. IO could Add a property called "fixiffromdelphi" (or something like that) and then add some code which ensures the child controls get placed correctly.
Ideally, this should happen under streamning, but I am not sure how to go about it. Is there anyway the parent (GroupBox) can access the subcontrols while the form streams in the dfm/lfm? And through that override e.g. top value?
How can I merge two VCL components together so I can access both of their properties?
For example, I want to merge a TImage and a TPanel into one, I require that the TPanel is the base component, so the TImage will be child to the TPanel.
Is it possible to do this?
I've been trying to do this in Delphi 2010 via Component > New VCL Component but it creates non-visual components when I require a visual component.
What can I do to change this?
If I understand correctly I think you want to merge two components together and expose the properties for both?
If this is what you are looking for, I asked a similar question for joining a TImage and TScrollBox together which can be found here:
Component Creation - Joining Components Together?
SetSubComponent was the key to achieving this, it may be worth while reading the comments and answers from the link above to understand more.
The Delphi language does not support multiple inheritance of implementation, only multiple inheritance of interface. Thus you cannot simply merge together two classes in the way you hope.
What you are proposing sounds a bit odd anyway. Both TPanel and TImage have their own visual surfaces. The only plausible thing I can imagine is that you could make the TImage a child of the TPanel. Derive a new component from TPanel. That component would create and own a TImage. Make the parent of the TImage sub control be the panel. Any properties and events of the TImage control that you want to surface in your control would have to be done manually. This is composition rather than inheritance.
You might use a TFrame to create a component that exists of other visual components at design time, e.g. a TPanel with a TImage upon it. This is probably not exactly what you want: the properties are not 'merged' together, you must design your own properties and methods to make this newly created component behave as you want it to. The functionality you desire (changing visual features depending on the spot of the mouse) needs to be built only once into the frame.
To thwart the nit-pickers, let me start with, I searched here with this and could not find an answer, and yes, also I did scroll through the "Similar questions."...
Adding shortcuts to a TForm
I want to drag and drop some shortcuts from the Desktop to a TForm in my application. I am using Anders Melander's brilliant Drag Drop Suite (DDS).
I tried putting a TImage on the form but the DDS does not drop to an Image so I added a TPanel with a TImage on it. I could then drop on the panel and assign the image to the TImage.Picture. Problem was the Panel has no Transparent Property so the shortcut on the form looks clunky with the visible Panel behind it.
I need to be able to drop to the TImage or make the underlying TPanel transparent.
Can anyone help with code-snippets for either of those options, or better yet, a method of dropping a Shortcut directly on to my Form.
Thanks
Coincidentally I needed to make a TWinControl (the base for every visible control with a window handle, including TPanel) transparent. I found numerous results and applied them to this answer.
It's been a while since I implemented drag and drop, but I assume you call some API and pass it the handle of the panel? That answers the question why you can't use TImage. TImage is a graphic control, a control without a handle, that relies on its parent for recieving messages and drawing itself.
It should be possible to use the form, though, since that has a handle too.
If the TImage is directly on the TForm, then let the TForm handle the drop, no TPanel needed. OLE Drag&Drop operations (which Ander's components implement) provide coordinates where dragging and dropping occurs. The TForm should be able to detect when a drag is over the area occupied by the TImage and what type of data is being dragged, and only allow dropping of supported types within that area, extracting the dropped data and updating the TImageas needed, and denying anything else that does not match that criteria.