Last week, a Matlab user asked whether it is possible to customize the context (right-click) menu that is presented in plot-edit mode. This menu is displayed by clicking the plot-edit (arrow) icon on the standard Matlab figure toolbar, then right-clicking any graphic/GUI element in the figure. Unfortunately, it seems that this context menu is only created the first time that a user right-clicks in plot-edit mode – it is not accessible before then, and so it seems impossible to customize the menu before it is presented to the user the first time.
A few workarounds were suggested to the original poster and you are most welcome to review them. There is also some discussion about the technical reasons that none of the “standard” ways of finding and modifying menu items fail in this case.
In today’s post I wish to repost my solution, in the hope that it might help other users in similar cases.
My solution is basically this:
- First, enter plot-edit mode programmatically using the plotedit function
- Next, move the mouse to the screen location of the relevant figure component (e.g. axes). This can be done in several different ways (the root object’s PointerLocation property, the moveptr function, or
- Next, automate a mouse right-click using the built in
java.awt.Robotclass (as discussed in this blog back in 2010)
- Next, locate the relevant context-menu item and modify its label, callback or any of its other properties
- Next, dismiss the context-menu by simulating a follow-on right-click using the same
- Finally, exit plot-edit mode and return the mouse pointer to its original location
% Create an initial figure / axes for demostration purpose fig = figure('MenuBar','none','Toolbar','figure'); plot(1:5); drawnow; % Enter plot-edit mode temporarily plotedit(fig,'on'); drawnow % Preserve the current mouse pointer location oldPos = get(0,'PointerLocation'); % Move the mouse pointer to within the axes boundary % ref: https://undocumentedmatlab.com/blog/undocumented-mouse-pointer-functions figPos = getpixelposition(fig); % figure position axPos = getpixelposition(gca,1); % axes position figure(fig); % ensure that the figure is in focus newPos = figPos(1:2) + axPos(1:2) + axPos(3:4)/4; % new pointer position set(0,'PointerLocation',newPos); % alternatives: moveptr(), java.awt.Robot.mouseMove() % Simulate a right-click using Java robot % ref: https://undocumentedmatlab.com/blog/gui-automation-robot robot = java.awt.Robot; robot.mousePress (java.awt.event.InputEvent.BUTTON3_MASK); pause(0.1) robot.mouseRelease(java.awt.event.InputEvent.BUTTON3_MASK); pause(0.1) % Modify the <clear-axes> menu item hMenuItem = findall(fig,'Label','Clear Axes'); if ~isempty(hMenuItem) label = '<html><b><i><font color="blue">Undocumented Matlab'; callback = 'web(''https://undocumentedmatlab.com'',''-browser'');'; set(hMenuItem, 'Label',label, 'Callback',callback); end % Hide the context menu by simulating a left-click slightly offset set(0,'PointerLocation',newPos+[-2,2]); % 2 pixels up-and-left pause(0.1) robot.mousePress (java.awt.event.InputEvent.BUTTON1_MASK); pause(0.1) robot.mouseRelease(java.awt.event.InputEvent.BUTTON1_MASK); pause(0.1) % Exit plot-edit mode plotedit(fig,'off'); drawnow % Restore the mouse pointer to its previous location set(0,'PointerLocation',oldPos);
In this code, I sprinkled a few pauses at several locations, to ensure that everything has time to fully render. Different pause values, or perhaps no pause at all, may be needed on your specific system.
Modifying the default context-menu shown in plot-edit mode may perhaps be an uncommon use-case. But the technique that I demonstrated above – of using a combination of Matlab and Java
Robot commands to automate a certain animation – can well be used in many other use-cases where we cannot easily access the underlying code. For example, when the internal code is encoded/encrypted, or when a certain functionality (such as the plot-edit context-menu) is created on-the-fly.
If you have encountered a similar use-case where such automated animations can be used effectively, please add a comment below.