Determine what UI Object Called a Context Menu

9 views (last 30 days)
This seems like a pretty basic question.
I have a pretty complex App created in App Designer. I have finally finished all of my basic functions I want it to do, but now I need to add some refinement and user customizations. I want to be able to do some of this via context menus.
I have 18 listboxes in my app. Each one can hold an arbitrary number of items that correspond to data variables used in the background and on plotting. I want to create ONE context menu that can be used on all 18 listboxes rather than creating 18 context menus.
Ideally, I'd love to be able to pass exactly which listbox item has been clicked on, BUT, I've seen that question already asked here: https://www.mathworks.com/matlabcentral/answers/789804-contextmenu-for-each-listboxitem without an answer.
All I really need to enable that is to be able to pass WHICH listbox the context menu was spawned from to the callback function. From there, I can have it do what I need. However, I looked through the documentation here: https://www.mathworks.com/help/matlab/ref/uicontextmenu.html and here: https://www.mathworks.com/help/matlab/ref/matlab.ui.container.contextmenu-properties.html and I looked at the event.Source object, and I can't seem to figure out how to get this information. The Parent object is the main UIFigure of the App itself, so that's way too high of a level to figure out which block the context menu was used in. It seems, since it's a context menu, that it should know the context in which it was spawned. How can I get this information to the callback? I really don't want to create 18 different context menus.
I guess I could figure out how do it programmatically... but then I can't use the GUI editor for it.
I feel like there should be an easier way - like a property I could check. If so, what is that property, or what kind of method / function could I use to identify the UI object that the menu was called from?
  1 Comment
Captain Karnage
Captain Karnage on 10 Jan 2023
FYI, I ended up doing a "brute force" loop in my StartupFcn to create 18 different Context menus, each specialized to the box they're spawned from. It won't be helpful to post all of my code here, as it depends on other functions I already created (mainly a function that can retrieve a handle any of the 18 boxes based on certain parameters) that are highly specialized to my app. But, basically, I use a set of loops that loops through the properties that define my boxes, then create a uicontextmenu with a UserData property equal to the properties of that box. All of the uimenu Children created also have the same UserData property. I then set a callback function (with requiresEventData set to true) for each child menu which reads event.Source.UserData and passes it on to the functions that I need to run based on the selection.
Here's an excerpt from inside my for loop. This creates a context menu with an opening call back and 3 selections, "Remove Variable", 'Set Variable Color", and an "Edit Variable" selection who's exact text depends on which box is calling it.
figApp = app.AppFigure;
callbackContext = createCallbackFcn(app, @menuVariablesContextMenuOpening, true);
menuContext = uicontextmenu(figApp, 'ContextMenuOpeningFcn', callbackContext, 'UserData', thisBox);
callbackRemove = createCallbackFcn(app, @removeVariable, true);
menuRemove = uimenu(menuContext, 'Text', 'Remove Variable', 'MenuSelectedFcn', callbackRemove, 'UserData', thisBox );
callbackColor = createCallbackFcn(app, @setVariableColor, true);
menuEdit = uimenu(menuContext, 'Text', 'Set Variable Color', 'MenuSelectedFcn', callbackColor, 'UserData', thisBox );
callbackEdit = createCallbackFcn(app, @editVariable, true);
menuEdit = uimenu(menuContext, 'Text', txtEdit, 'MenuSelectedFcn', callbackEdit, 'UserData', thisBox );
Some of the names:
figApp is a handle to the main app figure (named AppFigure in this example)
menuVariablesContextMenuOpening is my callback function for the menu opening
txtEdit is a contextual char array which is different for each box
thisBox is a struct with all the properties of each box that I need
This code is inside a set of loops that iterate a total of 18 times, so It creates 18 different context menus in my App, but the only thing that makes each menu different is the UserData (and text on the edit menu). They all call the same set of callback functions, which then uses event.source.UserData to differentiate which one is calling and what actions it should take.
If anyone else is looking for something similar, hopefully this helps. Kind of brute force, but at least I didn't have to sit and create 18 different context menus in App Designer. This way, it will be easy to make a change that will affect all 18 and not have to edit 18 different context menus, either.

Sign in to comment.

Answers (1)

Kevin Holly
Kevin Holly on 9 Jan 2023
Edited: Kevin Holly on 9 Jan 2023
Could you create a property variable that stores the handle of the last clicked listbox?
something such as:
properties
selected
end
app.listbox1.ClickedFcn = 'app.selected = app.listbox1'
app.listbox2.ClickedFcn = 'app.selected = app.listbox2'
app.listbox3.ClickedFcn = 'app.selected = app.listbox3'
...etc
  2 Comments
Captain Karnage
Captain Karnage on 10 Jan 2023
I just tested it and 'ClickedFcn' is only called on a left click, not a right click. So no, that would not work.
Captain Karnage
Captain Karnage on 10 Jan 2023
It's too bad, too, because if ClickedFcn did work, I'd have access to event.InteractionInformation.Item, which would tell me which item was clicked on as well.

Sign in to comment.

Categories

Find more on Interactive Control and Callbacks in Help Center and File Exchange

Products


Release

R2022b

Community Treasure Hunt

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

Start Hunting!