If no graphics objects are added to or removed from a figure, does findobj always generate the list in the same order?

2 views (last 30 days)
Hopefully my question is clear from the title, but I'll try to clarify what I mean.
Suppose I have a figure full of graphics objects and I want to gather all of these objects to perform some kind of function on each one.
hf = figure;
axes;
uicontrol;
hObjects = findobj(hf);
for i = 1:length(hObjects)
foo(hObjects(i));
end
Now suppose this array of graphics objects goes out of scope but later on, I want to perform some other function on each of these objects.
hf = gcf;
hObjects = findobj(hf);
for i = 1:length(hObjects)
bar(hObjects(i));
end
If I haven't added or removed any graphics objects from the figure (nor changed their Type), am I guaranteed the same list of objects from findobj? For example, if bar is the inverse function to foo in the sense that foo(bar(hObject)) == hObject is true for a given graphics object hObject, does the above code revert all my graphics objects to their original state in the end?
Thanks in advance for your answers!

Accepted Answer

Walter Roberson
Walter Roberson on 14 Jul 2021
If I haven't added or removed any graphics objects from the figure (nor changed their Type), am I guaranteed the same list of objects from findobj?
No.
uistack() can change the order of objects.
Making a figure current (such as by clicking on it) changes the order of objects -- I tested this for figures
I would not be at all astonished if making an object current by clicking on it, had the effect of raising it inside its container -- and likewise, its container inside the container of the container, and so on. Clicking a line probably moves the line to the top of its group, and moves the axes that the line is in to the top of its uipanel, and the uipanel to the top of its figure, and the figure to the top of the active figures. I have not tested this (only tested with figures), but it would not astonish me.
  5 Comments
Walter Roberson
Walter Roberson on 22 Jul 2021
You can save the handles that you got back from findObj somewhere, so that you could be sure of getting the exact handles back.
However... since you are setting all of the uicontrol except perhaps one button, then you do not care about order. Just set them all to disable, then set the one button to enable; to restore, set them all to enable (it won't matter that the one button was already set to enable.)
Wouter Van Werveke
Wouter Van Werveke on 22 Jul 2021
Edited: Wouter Van Werveke on 22 Jul 2021
Having looked back at my code, I've found that I had already implemented it this way. Except that I do, in fact, care about the order because not all uicontrols are necessarily enabled when the calculation starts and I want to make sure I don't enable anything that wasn't enabled before. Saving the handles from findobj at the start of the callback function then does indeed allow me to simply restore the original states at the end of the callback, when the lengthy calculation is finished.
However, there is another uicontrol (a checkbox) in my GUI which disables all uicontrols indefinitely, i.e. until the box is unchecked (don't ask me why). I (perhaps unwarrantedly) dislike storing all the uicontrol handles and their original states in the guidata of my GUI every time this checkbox is (un)checked. My current solution here is to store the object handles and original states in the UserData of the checkbox, which perhaps you might argue isn't much cleaner than storing them in the guidata. The onCleanup solution means I don't have to explicitly store this data anywhere, but I do have to create a field in the guidata to store the cleanup object, which I'm wondering how to weigh up against my current solution. I have to admit I am a little uncomfortable with writing something like
delete(handles.revertStates)
If I'm not mistaken, this means I am constantly creating and deleting this field when the checkbox is being checked and unchecked, or am I wrong about this? Not to mention that there could be references to a deleted field in other parts of the code (although there really shouldn't be - not at the moment at least). I'd be very interested to get your input on this!

Sign in to comment.

More Answers (1)

Jogesh Kumar Mukala
Jogesh Kumar Mukala on 14 Jul 2021
Hi,
If no graphics objects are added to or removed from a figure, the findobj always generates the list in the same order. The findobj always returns all the objects in a hierarchical manner.
By observing the example you provided, it seems you have a doubt about the order of the list after applying some function over graphics objects. To clarify regarding applying some functions over graphics objects, you may refer below attached code. You can refer isa to understand the function in the code.
plot(rand(5))
h = findobj;
% Generates the list before applying the function
h
for i =1:length(h)
foo(h(i));
end
% Generates the list after applying the function
k= findobj;
k
function foo(x);
if(isa(x, 'matlab.ui.Root'))
% Change the units of graphic object root as it doesnot have color property
x.Units = 'pixels';
elseif(isa(x,'matlab.graphics.chart.primitive.Line'))
% Change color of the graphic objects lines
x.Color = [1 1 0];
else
% Change color of the graphic object figure
x.Color = [1 1 1];
end
end
  2 Comments
Walter Roberson
Walter Roberson on 14 Jul 2021
fig = figure(1);
ax1 = axes(fig, 'tag', 'ax1');
ax2 = axes(fig, 'tag', 'ax2');
findobj(fig)
ans =
3×1 graphics array: Figure (1) Axes (ax2) Axes (ax1)
uistack(ax1,'top')
drawnow()
findobj(fig)
ans =
3×1 graphics array: Figure (1) Axes (ax1) Axes (ax2)
This example proves that uistack() can affect the order in which findobj() retrieves objects.

Sign in to comment.

Categories

Find more on Graphics Object Programming in Help Center and File Exchange

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!