- Undocumented Matlab - https://undocumentedmatlab.com -

Disabling menu entries in deployed docked figures

Posted By Yair Altman On November 14, 2012 | 14 Comments

Last week I presented an article [1] explaining how to solve an issue with deployed (compiled) Matlab applications. Today I’d like to welcome guest blogger Alexander Mering [2], who will explain how to disable standard Matlab menu items in deployed docked Matlab figures. Alexander has been an avid follower of this blog, and from his CSSM posts [3] we can tell that he’s been heavily using advanced GUI features presented in this blog. His article today nicely shows how we can use different building-blocks presented in different articles in this blog, to achieve something new and useful.
As Yair pointed out in many occasions, the power of Matlab could be greatly enhanced using the underlying Java mechanism. To me, while developing a larger standalone tool for technical calculations, these hints are worth a mint (as I guess for many of you).
One of these very useful hints is the ability to dock figure windows in standalone applications [4]. This perfectly fits to my understanding of a “clean desktop”, i.e., having as less as possible separate windows. Since in many calculations dozens of figures are generated, the desktop gets up crowded very fast – if these are not grouped. So docking is essential (at least for me). Unfortunately there seems to be a serious problem with the resulting menu entries (at least in R2011b on Win XP), leading to a crash of the standalone application. Based on the posts by Yair, I will sketch a possible route to avoid this issue.

The symptom

In the compiled application, docking could be accomplished by accessing the figure frame’s underlying Java level:

% get java frame for sophisticated modifications
jframe = get(handle(figure_handle), 'JavaFrame');
% allow docking
jframe.fHG1Client.setClientDockable(true)

Using this modification, the user is now allowed to dock and undock the figures manually. For initial docking of the figure,

javaFrame.fHG1Client.setClientWindowStyle(true,false)

could be used during figure creation. Unfortunately, there are menu entries in the Figures container which are either unwanted (since not usable) or even directly crash the standalone applications:

Useless Debug menu items in deployed applications
Useless Debug menu items in deployed applications

Menu items crashing deployed applications
Menu items crashing deployed applications

Since crashing menu entries will be found and used by end-users (though these are somehow hidden), these prohibit the usage of the docking feature as long as these could be invoked. So how can we disable / remove these menu items?

The unsuccessful solution

Unfortunately, the straight forward solution of getting the handle to the Figures containers’ menu bar and remove the unwanted items does not work. The reason for this is the (to me unexpected behavior) that the menu bar seems to be rebuilt whenever a figure is docked/undocked.
This is actually the same behavior that automatically rebuilds the Editor’s menu bar whenever an editor file is added/removed. The Editor container is basically the same docking container as the Figures container, as shown by Yair’s setFigDockGroup utility [5]:

Docking a figure in the Editor container (group)
Docking a figure in the Editor container (group)

Therefore, removing unwanted menu items only helps until the next figure docking/undocking. To make it even worse: also pressing any of the buttons within the document bar (if having more than one figure) somehow rebuilds the entire menu structure, reverting our changes. So the solution becomes a bit more complex.

The working solution

For the working solution, many pieces presented by Yair should be put together. The first piece results from the question how to detect a dock/undock event. Since no such callback is defined, we need to use a property listener as Yair showed in his post about the continuous slider callback [6]:

% listen to the WindowStyle property to detect docking / undocking events
hProp = findprop(handle(figure_handle),'WindowStyle');  % a schema.prop object
% if the event occurs, invoke the callback
hlistener = handle.listener(handle(figure_handle), hProp, 'PropertyPostSet',{@(source, event) Callback_DockingFcn});
% attach listener to the GUI since it needs to be known (as long as the figure exists)
setappdata(figure_handle, 'Handle_Listener', hlistener);

Now, whenever the figure’s WindowStyle property (which controls the docking state) is changed, our docking callback is invoked.
The next piece of the puzzle takes care of the menu rebuild whenever any document bar button is pressed. To overcome this behavior, the idea is to define the MousePressed callback of theses buttons to (again) invoke the docking callback. This is necessary for two reasons: First, pressing the button (i.e., changing the current figure) rebuilds the menu, overwriting our changed menu entries. Secondly, all other buttons are also somehow rebuilt and the callbacks are removed if a new figure is docked.
The handles to the document bar buttons could be found using Yair’s findjobj utility [7]. We have already seen that the Editor container is analogous to the Figures docking container. So let’s use the method described by Yair for accessing the Editor container [8], to access the Figures container:

figures_container = javaObjectEDT(matlab_instance.getGroupContainer('Figures'));
figures_frame = javaObjectEDT(figures_container.getTopLevelAncestor);

Once we get the Java Frame for the Figures container, the buttons could be found by digging through its children. This finally allows to set the callback using

DTDocumentBar = javaObjectEDT(figures_frame.getRootPane.getLayeredPane.getComponent(1).getComponent(1).getComponent(0).getComponent(0).getComponent(1).getComponent(0));
ContentPanel = javaObjectEDT(DTDocumentBar.getComponent(0).getComponent(0).getViewport.getView);
if ~isempty(ContentPanel.getComponents) % less than two documents are open and no DTDocumentbar exists
    drawnow; pause(0.05)
    GroupPanel = javaObjectEDT(ContentPanel.getComponent(0));
    GroupPanel_Elements = javaObjectEDT(GroupPanel.getComponents);
    % change the MousePressed Callback for each of the buttons to invoke the function which disables the menu
    for n = 1 : GroupPanel.getComponentCount
        thisElement = GroupPanel_Elements(n);
        if isequal(char(thisElement.getClass.toString), 'class com.mathworks.widgets.desk.DTDocumentBar$DocumentButton')
            set(handle(thisElement, 'CallbackProperties'), 'MousePressedCallback', {@(source, event) Cbrake_Callback_Diagrams_DockingFcn})
        end
    end
    drawnow; pause(0.05)
end

where the loop runs through the current buttons in the document bar.
As the last step of our procedure, we finally remove (or disable) the menu entries which are unwanted. This is achieved by extracting the handle to the Figures menu by:

figures_menu = javaObjectEDT(figures_frame.getJMenuBar);

Running through the menu items, searching for the unwanted entries (as long as they have pre-defined menu-item names [9]) at the end sets us into the position to take care of the menu items:

% run through top-level menu items
for n = 1 : figures_menu.getMenuCount
    % completely deactivate Debugging options
    if isequal(char(figures_menu.getMenu(n-1).getName), 'DesktopDebugMenu')
        DesktopDebugMenuPos = n - 1;
    end
    % Remove some items from the Desktop menu
    if isequal(char(figures_menu.getMenu(n-1).getName), 'DesktopMenu')
        desktop_menu = javaObjectEDT(figures_menu.getMenu(n-1));
        DeletePos = [];
        for m = 1: desktop_menu.getMenuComponentCount
            if ismember({char(desktop_menu.getMenuComponent(m-1).getName)}, ...
                        {'ToggleFigure PaletteCheckBoxMenuItem', 'TogglePlot BrowserCheckBoxMenuItem', 'ToggleProperty EditorCheckBoxMenuItem'})
                DeletePos(end+1) = m - 1;
            end
        end
        for m = length(DeletePos) : -1 : 1
            desktop_menu.remove(DeletePos(m))
        end
    end
end
% finally remove the "Debug" menu
if ~isempty(DesktopDebugMenuPos)
    figures_menu.remove(DesktopDebugMenuPos)
end

Since this callback is invoked whenever a figure is docked/undocked, or the currently shown figure is changed (by pressing the document bar button), all unwanted menu items within the Figures menu could be removed.
As a result, the new Figures container menu looks like:

Deployed menu without unwanted items
Deployed menu without unwanted items

Remarks

I must admit that above solution is still imperfect. For instance, sometimes there is a larger delay between the docking (or button press event) and the removing of the menu item. Nevertheless, this solution allows me to distribute my standalone with docked figures without having menu items directly leading to a fatal error.
Obviously, the solution has some positive side effects:

  • As could be seen from the screen shot, the Matlab desktop becomes available also within your compiled applications. This might be wanted. If not, it could be removed the same way as the other menu items. One drawback of making the desktop available should be mentioned: In my tests, the standalone Matlab desktop shows the whole list of recent files I have in the Matlab editor at compile time. This is somehow ugly but not that problematic.
  • Additional menu items could be added, giving more possibilities for modifications.

I have uploaded a first version of the docking and creation functions, together with a small test project, to the Matlab file Exchange [10]. Readers are welcome to download the code and send me improvement suggestions. Or you could simply leave a comment [11] below.

Categories: Figure window, Guest bloggers, High risk of breaking in future versions, Java, Listeners, Undocumented feature


14 Comments (Open | Close)

14 Comments To "Disabling menu entries in deployed docked figures"

#1 Comment By Alexander On November 15, 2012 @ 03:14

As Aurelien just pointed out on the FEX, I do have a wrong definition of the MousePressedCallback. I overlooked it when extracting it from my project. So,

 set(handle(thisElement, 'CallbackProperties'), 'MousePressedCallback', {@(source, event) Cbrake_Callback_Diagrams_DockingFcn})

should be changed to

 set(handle(thisElement, 'CallbackProperties'), 'MousePressedCallback', {@(source, event) Callback_DockingFcn})

I already made an update to the FEX.

#2 Comment By Raja Amirthalingam On February 15, 2014 @ 14:18

Hi,

In the Callback_DockingFcn of yours, I am getting error in the line.

DTDocumentBar = javaObjectEDT(figures_frame.getRootPane.getLayeredPane.getComponent(1).getComponent(1).getComponent(0).getComponent(0).getComponent(1).getComponent(0));

Can you tell me whats wrong?

Thanks.

Raja

#3 Comment By Yair Altman On February 15, 2014 @ 14:26

@Raja – as you can see from this complex line, it highly depends on the exact container hierarchy and so it is not surprising that it may be slightly different on a different platform and/or Matlab release. You will need to carefully look at the various elements to check how to modify it for your particular needs. A good way to see this is to run the following code in your Matlab command prompt after the figure is displayed:

figures_frame.getRootPane.getLayeredPane.list

You will see the hierarchy of the sub-containers and you can easily navigate them via .getComponent(index). Just remember that index 0 means the first child, 1 means the second etc.

If you need professional help, consider employing my consulting services. Use the email link at the top of this page.

#4 Comment By Raja Amirthalingam On February 15, 2014 @ 15:18

Hi Yair,

It is taking a long time to execute this command, any idea?

Thanks.

Raja

#5 Comment By Raja On March 19, 2014 @ 16:22

Hi Yair,

I figured it out using your suggestions.

I am still fixing some issues, but I get the general Idea.

Thanks!
Raja

#6 Comment By Raja On March 19, 2014 @ 16:26

Hi Yair,

There is one little issue. When docking and undocking, the menu comes back. Is it possible to add a listener to the ComponentCount Property of the Menu Bar?

Thanks.
Raja

#7 Comment By Yair Altman On March 20, 2014 @ 00:49

@Raja – try using ComponentAddedCallback or ComponentRemovedCallback. See [18].

#8 Comment By Thierry Dalon On March 27, 2014 @ 01:10

Instead of

DTDocumentBar = javaObjectEDT(figures_frame.getRootPane.getLayeredPane.getComponent(1).getComponent(1).getComponent(0).getComponent(0).getComponent(1).getComponent(0));

one could use the great [19]:

hDocumentButtons=findjobj(container,'class','DTDocumentBar$DocumentButton');

or for Matlab >=R2012a:

hTabs=findjobj(container,'class','DTDocumentTabs$Tab');

You can also view the elements structure by using findjobj without outputs.

#9 Comment By haya On January 29, 2015 @ 07:47

hi
I’m having a similar yet different issue.
on my deployed application the user can generate plots(figures).
The figures which are generated on the compiled application has only ‘File’ in the MenueBar and does not have all the options on the ToolBar. The one which is mostly required is the ‘arrow’, with which the user can choose part of the figure such as the legend window, title, axes and edit them and their properties.
Obviously, when running on matlab the figure has all its tools.
I’m looking for a way to display and enable menu/tool entries in deployed figure

#10 Comment By Yair Altman On January 29, 2015 @ 08:09

@Haya – the interactive plot editing functionality is not enabled in deployed application. You will need to do this programmatically in your code if you need it in the deployed app.

#11 Comment By haya On February 1, 2015 @ 02:19

@Yair -first, thank you for your answer
This is precisely what i’m asking, I can I do this programmatically?
I compiled my code with MATLAB and I it as an .exe process from my .Net application.
The user can generate figures from the MATLAB .exe which is hosted in my .Net app, but once the figure opens it is missing the ‘Exploration.Pan’ option in the tools bar and also all option in the menu bar but the ‘File’
Any idea how to do this programmatically?

#12 Comment By Yair Altman On February 1, 2015 @ 10:44

@Haya – you did not understand. The plot-editing functionality does not exist in deployed apps. You cannot simply restore the menu item because the functionality itself does not exist. You will need to program the entire functionality yourself if you wish (yes of course it is very difficult, quite possibly not worth all the effort).

#13 Comment By haya On February 1, 2015 @ 23:28

@Yair thank you again for your answer.
I have no idea how to and from where to start this kind of code and unfortunately I must have the plot-edit functionality on my deployed app. If you have any idea how I can get started I’ll be happy to hear.
Thank you again
haya

#14 Comment By alsec On March 24, 2018 @ 22:47

Thanks for that.


Article printed from Undocumented Matlab: https://undocumentedmatlab.com

URL to article: https://undocumentedmatlab.com/articles/disabling-menu-entries-in-deployed-docked-figures

URLs in this post:

[1] article: http://undocumentedmatlab.com/blog/removing-user-preferences-from-deployed-apps/

[2] Alexander Mering: http://www.mathworks.com/matlabcentral/fileexchange/authors/208302

[3] CSSM posts: https://www.mathworks.com/matlabcentral/newsreader/search_results?dur=all&search_string=authorid%3A146471

[4] dock figure windows in standalone applications: http://undocumentedmatlab.com/blog/docking-figures-in-compiled-applications/

[5] setFigDockGroup utility: http://www.mathworks.com/matlabcentral/fileexchange/16650-setfigdockgroup

[6] continuous slider callback: http://undocumentedmatlab.com/blog/continuous-slider-callback/

[7] findjobj utility: http://undocumentedmatlab.com/blog/findjobj-find-underlying-java-object/

[8] accessing the Editor container: http://undocumentedmatlab.com/blog/accessing-the-matlab-editor/

[9] menu-item names: http://undocumentedmatlab.com/blog/modifying-default-toolbar-menubar-actions/

[10] Matlab file Exchange: http://www.mathworks.com/matlabcentral/fileexchange/39026-figures-menu-adaption-for-standalone-applications

[11] leave a comment: http://undocumentedmatlab.com/blog/disabling-menu-entries-in-deployed-docked-figures#respond

[12] Docking figures in compiled applications : https://undocumentedmatlab.com/articles/docking-figures-in-compiled-applications

[13] Using pure Java GUI in deployed Matlab apps : https://undocumentedmatlab.com/articles/using-pure-java-gui-in-deployed-matlab-apps

[14] Matlab toolstrip – part 9 (popup figures) : https://undocumentedmatlab.com/articles/matlab-toolstrip-part-9-popup-figures

[15] JGraph in Matlab figures : https://undocumentedmatlab.com/articles/jgraph-in-matlab-figures

[16] Removing user preferences from deployed apps : https://undocumentedmatlab.com/articles/removing-user-preferences-from-deployed-apps

[17] Splash window for deployed applications : https://undocumentedmatlab.com/articles/splash-window-for-deployed-applications

[18] : https://undocumentedmatlab.com/blog/uicontrol-callbacks/

[19] : https://undocumentedmatlab.com/blog/findjobj-find-underlying-java-object/

Copyright © Yair Altman - Undocumented Matlab. All rights reserved.