- ROI object handles are saved as a private (or public) property of the app.
- Every ROI object is assigned a unique tag name.
- The context menu is assigned to every ROI object.
- A listener is added to each ROI object and responds to a button click (right or left mouse).
- When the ROI is clicked, it updates the context menu tag to match the tag of the clicked ROI.
- When the cxMenuSelectionFcn is evoked by a right-button click, the function uses the recently updated context menu tag and matches it with all ROI tags to identify what object evokes the menu.
Handle of UI component from which a context menu has been opened
19 views (last 30 days)
Show older comments
Bruno Gonfiotti
on 7 Oct 2020
Answered: Jasmine Poppick
on 20 Sep 2023
Dear all,
I spent the last hour looking for a solution to this problem but I've not found anything useful. I have a very simple problem, and probably the solution is easy as well: I have a context menu shared among several UI components. How can I get an handle of the object for which the context menu has been opened? I can't use different context menus because the UI components are created interactively.
EDIT: I try to explain a little bit better my issue. I have a GUI created with App Designer. The GUI shows an image on which the user can draw several ROIs (line, boxes, etc.). The same context menu is attached on each ROI and contains two items only: rename and delete object. My point is: when I click on "rename" how can I get the handle of the element from which the context menu has been opened? I tried to setup the "ContextMenuOpeningFcn" but it doesn't work (the function is not called when the menu is opened).
Thank you for your help!
0 Comments
Accepted Answer
Adam Danz
on 7 Oct 2020
Edited: Adam Danz
on 7 Oct 2020
Neither the cxMenuSelectionFcn nor the ContextMenuOpeningFcn functions indicate the object that evoked the context menu.
Check out Adam's excellent wrapper function but you'll need to make two important modifications that I listed in the comments under his answer.
Using gco or gcbo are other useful alternatives but they do not recognize ROI objects.
After some thinking, I came up with another way to identify which ROI objects evoked the context menu explained below. But this was before discovering Adam's (the other Adam) answer suggested above. I'd try that one first.
Method
Demo
The cxMenuSelectionFcn merely changes the color of the ROI. The full app is attached. Here are the key parts.
The variable containing the ROI handles is a private (or public) property of the app.
properties (Access = private)
ROIhandles=gobjects(1); % Stores ROI handles, produced in startupFcn
end
The startupFcn creates the context menu, plots the ROI objects, and assigns the listeners to the ROI objects. This could be done in any callback function. Importantly, unique tags must be assigned to the ROI objects and the context menu must exist prior to assigning the listeners.
% Code that executes after component creation
function startupFcn(app)
% Create context menu
cm = uicontextmenu(app.UIFigure);
m1 = uimenu(cm,'Text','ChangeColor','MenuSelectedFcn',@(mn,ad)cxMenuSelectionFcn(app,mn,ad));
% Plot 3 ROIs
% Assign unique tags to each ROI.
hold(app.UIAxes,'on')
app.ROIhandles(1) = images.roi.Rectangle(app.UIAxes,'Position',[.1 .1 .2 .2],'Tag','R1');
app.ROIhandles(2) = images.roi.Rectangle(app.UIAxes,'Position',[.5 .5 .1 .2],'Tag','R2');
app.ROIhandles(3) = images.roi.Rectangle(app.UIAxes,'Position',[.1 .6 .2 .3],'Tag','R3');
% Assign context menu to all ROIs (or any object that has a unique tag)
% This must come after assigning tags and before adding listeners below.
set(app.ROIhandles, 'ContextMenu', cm)
% Add listeners to the ROI objects.
% The listening will respond when the ROI obj is clicked (right or left mouse button)
% When clicked, the context menu tag will be changed to match the ROI's tag. This will
% inform the context menu selection function which object evoked it.
for i = 1:numel(app.ROIhandles)
app.ROIhandles(i).UserData = listener(app.ROIhandles(i), 'ROIClicked', ...
@(~,~)set(app.ROIhandles(i).ContextMenu,'Tag', app.ROIhandles(i).Tag));
end
end
Define the cxMenuSelectionFcn function
This is a private (or public) method defined in the App. Two assert()'s are used to make sure a tag was successfully assigned to the context menu and that one and only one ROI object was matched to the tag. It then changes the color of the ROI object to some random color.
methods (Access = private)
function cxMenuSelectionFcn(app,menu,~)
% cxMenuSelectionFcn; responds to selecting "ChangeColor" in context menu
% The context menu is assigned to ROI objects.
% Get ContextMenu tag
cmtag = menu.Parent.Tag;
assert(~isempty(cmtag),'Failure to assign tag to context menu.')
% get handle associated with tag
handleIdx = strcmp({app.ROIhandles.Tag}, cmtag);
assert(sum(handleIdx)==1, 'Failture to identify ROI.')
hRoi = app.ROIhandles(handleIdx);
% Change color of ROI
hRoi.Color = rand(1,3);
end
end
4 Comments
More Answers (2)
Jasmine Poppick
on 20 Sep 2023
Starting in R2023b, the MenuSelectedFcn and ContextMenuOpeningFcn callback event data contains the UI component that was right-clicked to open the context menu, stored in the ContextObject property.
For example, if you run this code and open the context menu on the button, the callback displays the Button object.
fig = uifigure;
cm = uicontextmenu(fig,ContextMenuOpeningFcn=@(src,event)disp(event.ContextObject));
m = uimenu(cm,Text="Menu");
btn = uibutton(fig,ContextMenu=cm);
0 Comments
Paola De Cecco
on 23 Jan 2023
One alternative could be to set UserData on all the context menus to the event Source parent.CurrentObject.
then you can read from UserData of each of the context menu, the handle of the uicontrol that created the context menu.
function ContextMenuOpening(app, event)
disp('can I get the menu owner here?')
L=length(event.Source.Children)
for i=1:L
set(event.Source.Children(i),'UserData',event.Source.Parent.CurrentObject);
end
end
0 Comments
See Also
Categories
Find more on Migrate GUIDE Apps in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!