matlab uimenu callback is detected by the wrong uicontextmenu when using the keyboard-shortcut (accelerator)

조회 수: 7 (최근 30일)
Example code here, followed by description.
createApp()
% preparation: create the app and select two different uitreenodes, one for each uitree.
% good behaviour: [right click] on the uitreenode and execute the call of context menu
% bad behaviour: now instead perform the [shortcut] ctrl+F
% 'swapping' the uifigure.children to give priority to the right context
% is not a practical solution because it reloads the app graphic
% and collapses the treenodes if they are nested
%%
function createApp()
F = uifigure(HandleVisibility="on");
L = uigridlayout(F,[1 2]);
createModuleInMyApp(1);
createModuleInMyApp(2);
function createModuleInMyApp(k)
tree = uitree(L);
cm = uicontextmenu(F,UserData="n° "+k);
for i=0:2
text = char('A'+i);
uitreenode(tree, Text=""+text+k, UserData="n° "+k);
end
uimenu(cm,Text="print me",UserData="n° "+k,Accelerator='F',MenuSelectedFcn={@example, k});
tree.ContextMenu = cm;
end
function example(src, ~, varargin)
disp("user selected object")
gco % < treenode correctly clicked
disp("object that is executing callback")
gcbo() % < context menu: wrong when using ctrl+F, right when right click mouse
disp("id of context menu: "+src.UserData)
disp("associated data with callback k: "+varargin{1})
end
end
Context: I have a group of tools that work independently, and the task is to integrate their respective user interfaces in a modular way — depending on the user needs, modules should be added or removed within a single uifigure.
The individual user interfaces are sometimes equipped with uicontextmenu: buttons/menus/uicontrols are the targets of the uicontextmenu, and indeed the menu only opens and options are shown when the user right-clicks on the correct component, not anywhere on the figure. However, the parent of the uicontextmenu is still the uifigure — so when the interfaces are combined, the general figure accumulates all the uicontextmenu elements. Sometimes, multiple uicontextmenu options share the same shortcuts — for instance, (Ctrl+F) performs one action for one module and something else for another. The callbacks are numerous and varied, so we would prefer to maintain the configuration with multiple uicontextmenu instead of merging them all into one — the tools might be in separate repositories, and keeping the code isolated is the preferred approach when it comes to making changes to individual modules.
Note: the modules within a single uifigure work correctly when using the mouse — right-clicking. I assume that this way, MATLAB forces the figure to access the uicontextmenu assigned to the component.
Problem: The malfunction occurs when, after selecting a certain component, for example a uitreenode, a keyboard shortcut is performed. In my current situation, and from what I understand from the example I'm sharing, the shortcut is not detected by the uicontextmenu associated with the selected object, but rather by the first uicontextmenu found in uifigure.Children. As a result, it carries incorrect information and performs actions targeting the wrong component.
Not a valid Solution: If I reorder the accumulated uicontextmenu elements in the uifigure, I would be able to match the situation I care about. However, there's a problem — reordering the children of the uifigure triggers a graphical refresh of the entire app (and presumably an internal rehash of callbacks), which resets the interface aesthetics (e.g., collapses all uitree nodes, clears text boxes), making the user experience frustrating.
Question: Is there something I haven't considered? Are there alternative solutions?

답변 (1개)

Nithin
Nithin 2025년 6월 11일
The reason you're observing this unexpected behavior is due to how MATLAB handles keyboard shortcuts (accelerators) in "uicontextmenu" objects. These shortcuts are not scoped to the specific UI component that the context menu is assigned to. Instead, accelerators are registered at the "uifigure" level. As a result, when you press a shortcut like "Ctrl+F", MATLAB searches through all "uicontextmenu" objects in the figure and triggers the first one it finds with a matching shortcut, regardless of which component is currently selected.
A workaround is to bypass the "uicontextmenu" built-in accelerator logic and handle keyboard shortcuts manually using the figure’s "WindowKeyPressFcn". This allows detecting the currently selected object, determining its associated module, and correctly dispatching the shortcut to that module's callback.
To associate UI components (like trees) with module identifiers, a "containers.Map" is used with uniquely generated string keys using a helper function "handle2hash", which converts graphics handles to string format:
Refer to the following steps to understand the changes needed:
  • Replace accelerator aogic with a manual key handler, instead of relying on "uicontextmenu" accelerators:
F.WindowKeyPressFcn = @(src, event) shortcutHandler(event, moduleTrees);
  • Now, track which module owns which tree by maintaining a "containers.Map":
moduleTrees = containers.Map('KeyType', 'char', 'ValueType', 'int32');
moduleTrees(handle2hash(tree)) = k;
  • Then, create a custom shortcut handler which identitfies the selected tree on shortcut press:
selectedObj = gco;
parentTree = ancestor(selectedObj, 'matlab.ui.container.Tree');
  • Since MATLAB graphics handles can't be used directly as containers.Map keys, use "handle2hash" to generate unique map keys:
function key = handle2hash(h)
key = sprintf('handle_%s', num2str(double(h)));
end
  • Finally, dispatch the correct module’s callback once the selected tree and its module ID are known:
example(struct('UserData', "n° " + k), [], k);
Kindly refer to the following MATLAB documentation for better understanding and the attached file for complete implementation

카테고리

Help CenterFile Exchange에서 Interactive Control and Callbacks에 대해 자세히 알아보기

제품


릴리스

R2024b

Community Treasure Hunt

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

Start Hunting!

Translated by