3

In MATLAB R2019a (Update 2), when using the following code, the axes toolbar is not shown when selecting Tab2 or Tab3.

classdef test < handle
    properties
        Ax
    end
    methods
        function self = test()
            f = figure;
            tg = uitabgroup(f, 'SelectionChangedFcn', @self.onSelectionChanged);
            t1 = uitab(tg, 'Title', 'tab1');
            uitab(tg, 'Title', 'tab2');
            uitab(tg, 'Title', 'tab3');
            self.Ax = axes(t1);
        end

        function onSelectionChanged(self, ~, e)
            self.Ax.Parent = e.NewValue;

        end
    end
end

I would like to know how to make the toolbar appear in the selected tab.

Edit: The following code shows the problem better: The axes toolbar is stucked in the first panel, while the axes is in second panel. However, to reproduce this, don't copy and paste into your MATLAB command window. It only happens if the axes' parent changes after the axes toolbar is drawn. Thus I split the code into two sections:

f = figure;
p1 = uipanel(f, 'Units', 'normalized', 'Position', [0 0 .5 1]);
p2 = uipanel(f, 'Units', 'normalized', 'Position', [.5 0 .5 1]);
ax = axes(p1);

And now change the axes' parent:

ax.Parent = p2;

Here is the result:Result after re-parenting the axes

And here is what I expect:

expected result

So far, I haven't figured out how to trigger the event that puts the toolbar in the correct position.

Neither changing the Visible property of the figure, axes, axtoolbar or uipanel helped. Also, overriding the toolbar by a new one does not help.

Patrick Happel
  • 1,336
  • 8
  • 18
  • The `toolbar` is a child of the `figure`, not the `axes`. – Hoki Jun 18 '19 at 08:42
  • @Hoki: The toolbar's `Parent` property points to the `axes` and the `figure`'s `Children` property only contains the `tabgroup`. Furthermore, the toolbar does not have something like a `Position` property... – Patrick Happel Jun 18 '19 at 08:48
  • @Hoki: Maybe you mixed it up. I'm talking about the relatively new axes toolbar as generated by `axtoolbar`. – Patrick Happel Jun 18 '19 at 08:49
  • I can reproduce the problem. [This blog post](https://undocumentedmatlab.com/blog/improving-graphics-interactivity) might be relevant. – Dev-iL Jun 18 '19 at 08:54
  • You should add that the toolbar is "stuck" on the first tab/panel where it appears. If you switch tabs/panels before showing it, it'll be (only) in the new position. – Dev-iL Jun 18 '19 at 09:18

3 Answers3

3

I have some bad news and some good news: based on my attempts it appears that one cannot move the same toolbar between containers (tabs or panels) due to a MATLAB restriction, however, a workaround is possible. Below is the details of how I reached this conclusion.


Upon investigating this a bit, I noticed that several properties of the AxesToolbar change after it is shown for the first time, two of them caught my eye - HasTrueParent and NodeParent.

Aha. So the toolbar now has a parent, which means that somewhere in the hierarchy of children, the tab should see the toolbar. Let's investigate further:

I've added another property to your class called, Tabs, and this is how I populate it in the constructor:

      self.Tabs(1) = uitab(tg, 'Title', 'tab1');
      self.Tabs(2) = uitab(tg, 'Title', 'tab2');
      self.Tabs(3) = uitab(tg, 'Title', 'tab3');
      self.Tabs = handle(self.Tabs);

Then, setting after setting (and hitting) a breakpoint we can see that:

K>> allchild(self.Tabs(1))
ans = 
  2×1 graphics array:

  AnnotationPane
  Axes
K>> allchild(self.Tabs(2))
ans = 
  0×0 empty GraphicsPlaceholder array.

Notice that AnnotationPane? This is the layer that contains annotation and probably also the toolbar. How can we know for sure? We can set its Visibility to 'off', and the toolbar stops appearing.

So naturally, one might be tempted to change the Parent of that pane, but this results in the error:

Error using matlab.graphics.shape.internal.AnnotationPane/setParentImpl
Cannot change parent of AnnotationPane object.

So what can be done about this? If you create new axes in every new tab,

hFig = figure();
hTG = uitabgroup(hFig);
for iTab = 1 : 3
    hTab = uitab(hTG, 'title', "Tab" + iTab);
    hPanel = uipanel(hTab);
    hAxes(iTab) = axes(hPanel);
end

their toolbars will be created correctly. From there, it's a matter of relocating the children (of the axes) and updating the limits/viewport.

Dev-iL
  • 23,742
  • 7
  • 57
  • 99
  • The problem with your workaround is the number of axes that are created. As the [blog post](https://undocumentedmatlab.com/blog/improving-graphics-interactivity)(you mentioned above) shows, this can lead to performance problems. The blog post was the reason why I want to re-parent the `axes`. – Patrick Happel Jun 18 '19 at 13:01
3

Since I considered the behaviour described above a bug, I have filed it to Matlab staff.

They responded to get around this issue, one shoud re-set the Parent of the axes toolbar. In case of the test class from above:

function onSelectionChanged(self, ~, e)
    self.Ax.Parent = e.NewValue;
    set(self.Ax.Toolbar,'Parent',[],'Parent',self.Ax);
end
Patrick Happel
  • 1,336
  • 8
  • 18
1

Here is another answer from my previous comment:

Another solution is to put the axes in a uipanel (which is good practice anyway) and then re-parent the panel:

classdef test < handle
    properties
        Ax
    end
    methods
        function self = test()
            f = figure;
            tg = uitabgroup(f, 'SelectionChangedFcn', @self.onSelectionChanged);
            t1 = uitab(tg, 'Title', 'tab1');
            uitab(tg, 'Title', 'tab2');
            uitab(tg, 'Title', 'tab3');
            self.Ax = axes(uipanel(t1)); % uipanel as axes parent
        end

        function onSelectionChanged(self, ~, e)
            self.Ax.Parent.Parent = e.NewValue; % re-parent the uipanel

        end
    end
end
Patrick Happel
  • 1,336
  • 8
  • 18