Hello again!
Help please solve the problem:
For example, I have a scene like this with UI:
How can I collect all TCastleRectangleControl by pascal code?
Hello again!
Help please solve the problem:
For example, I have a scene like this with UI:
How can I collect all TCastleRectangleControl by pascal code?
You mean the function with the TCastleUserInterface
as argument and the array of TCastleComponent
as Result
, for example?
something like this:
var
rootElement: TCastleUserInteface;
elementsList: Array of TCastleRectangleControl;
begin
rootElement:= DesignedComponent('SceneMain') as TCastleUserInteface;
...
{ do something, I don't know what
for filling elementsList }
...
elementsList; // filled
{ do any with this List }
end;
You can iterate, recursively, over the list of TCastleUserInterface children → to do any kind of searching.
This can be as simple as this: (adjusted code from ForceFallbackLook ):
procedure DoSomethingOnEachRectangle(const Ui: TCastleUserInterface);
var
Child: TCastleUserInterface;
begin
if Ui is TCastleRectangleControl then
begin
// do something on TCastleRectangleControl(Ui), or add it to a list
TCastleRectangleControl(Ui).Xxx := ...;
end;
for Child in Ui do
DoSomethingOnEachRectangle(Child);
end;
To iterate over all TCastleRectangleControl in a given view (whether created from code, or loaded from design) can use this with TCastleView instance as argument for DoSomethingOnEachRectangle
. To iterate over absolutely everything visible now, you can pass all items from Window.Controls
.
Ah, I see you mentioned rootElement
and a list. So it would go like this:
type
TCastleRectangleControlList = {$ifdef FPC}specialize{$endif} TObjectList<TCastleRectangleControl>;
procedure TMyView.Start;
var
Rects: TCastleRectangleControlList;
procedure EnumRects(const Ui: TCastleUserInterface);
var
Child: TCastleUserInterface;
begin
if Ui is TCastleRectangleControl then
Rects.Add(TCastleRectangleControl(Ui));
for Child in Ui do
EnumRects(Child);
end;
begin
inherited;
Rects := TCastleRectangleControlList.Create(false);
try
EnumRects(RootElement);
{ use Rects }
finally
FreeAndNil(Rects);
end;
end;
WHAT?! I can iterate UI elements with for…in cycle? Really? So easy?
Before I was try to use TCastleUserInterface.Component[i] as TComponent and always got some gibberish classes… for TCastleTransform it was fork fine…
OK I’ll try do it with for…in
{ 2min late }
O my Gosh! Its really working! Thanks!!!
I’m happy my info helped
As for the TCastleUserInterface.Component[I]
– it will iterate over components “owned”. Which may, or may not, be what you’re looking for. See https://forum.castle-engine.io/t/cge-inside-delphi-for-beginner/ thread for my recent explanation how “ownership” differs from “visual hierarchy” in CGE (similar to LCL / VCL / FMX actually).
But, long story short, yeah, you want to iterate over visual hierarchy which means just for Child in Ui ...
is what you need
Phew! I figured out how to do it:
function GetAllUIImages(const rootItem: TCastleUserInterface): Array of TCastleImageControl;
type
TItemsStack = {$ifdef FPC}specialize{$endif} TObjectStack<TCastleUserInterface>;
var
item, child: TCastleUserInterface;
items: TItemsStack;
begin
Result:= [];
items:= TItemsStack.Create(False);
items.Push(rootItem);
{ iterate over all elements of tree }
while (items.Count > 0) do
begin
item:= items.Pop;
for child in item do
items.Push(child);
{ pick up target }
if (item is TCastleImageControl) then
Insert((item as TCastleImageControl), Result, 0);
end;
FreeAndNil(items);
end;
For me main problem there was to understand which base class use to iterate on.
Although if I search for TCastleScenes in 3D objects, then I need to iterate over by the TComponent class not TCastleTransform, which is not obvious for me
However, as I understand it, this is related with choice of “visual/unvisual hierarchy”.
PS: Ah yes, I’m already collect TCastleImageControl instead of TCastleRectangleControl, but solve is same. Tasks change over time.
To find TCastleScene, knowing a TCastleViewport instance, one could do this:
procedure FindScenes(const ParentTransform: TCastleTransform);
var
ChildTransform: TCastleTransform;
begin
if ParentTransform is TCastleScene then
begin
// ... do something with TCastleScene(ParentTransform)
end;
// iterate recursively
for ChildTransform in ParentTransform do
FindScenes(ChildTransform);
end;
FindScenes(MyViewport.Items);
If one doesn’t know MyViewport
and/or wants to do this for all viewports – then first the code similar to previous posts can be used, i.e. TCastleViewport
is another TCastleUserInterface
hierarchy, so you can find all viewports within the UI hierarchy by iteration as shown in above posts.
This is more-or-less what the CGE editor is also doing to display the hierarchy on the left So it’s really complete.