对于用户界面,我正在编写 uitable
.用户在第一列中选择一个选项 A、B 或 C,第二列中的子选项取决于第一列中的选择,A.1、A.2 或 A .3 或 B.1、B.2 或 B.3 或 C
表格的代码可以在附录A中找到。
当用户首先定义主要选项时,子选项会自动相应地减少为只有有效的选择。这是通过评估 CellEditCallback
来实现的对于第 1 列并重置 ColumnFormat
对于第 2 列。(附录 B 中的函数 modifySelection
)
如果用户现在意识到他犯了错误并需要再次编辑子选项,那么 ColumnFormat
仍然根据先前编辑的主要选项设置并且有效选择不可用,除非他再次重新选择主要选项。 (请参阅图片中的蓝色突出显示部分)。
为了解决这个问题,我还实现了 CellSelectionCallback
调用函数 justifySelection
(在 附录 B 中),它通过选择检查,在第 1 列中选择了哪个选项以再次为第 2 列提供正确的子选项。但是由于此回调对选择使用react,我需要选择 两次,一次触发CellSelectionCallback
另一个真正让我做出选择。对于大表,这可能非常烦人!
所以我的问题是:
有没有办法阻止第2列的弹出菜单弹出,直到它找到相应的第1列的内容,然后立即提供有效的选择?
或者:
我如何检测鼠标点击单元格并获取行和列索引?但是没有调用下面的选择和弹出 Action ?
我已经在收集所有 available properties但没有发现任何有用的东西。
也许可以使用 ButtonDownFcn
做点什么,但如何获得单元格索引?那BusyAction
呢?属性(property),它怎么能用于我的目的?
有什么想法吗?
很抱歉提前用这么多代码轰炸你,它已经是最小的例子,但是完全可执行,所以你可以试试看。
附录 A/B
function fancyUitable
selector_1 = { 'A'; 'B' ; 'C' };
selector_2 = { 'first select first row!' };
h = figure('Position',[200 100 268 120],'numbertitle','off','MenuBar','none');
defaultData = repmat( {'select main option...', 'select suboption...'} ,5,1);
columnname = {'Option ',...
'Suboption '};
columnformat = { {selector_1{:}}, selector_2 };
columneditable = [true true];
t = uitable(h,'Units','normalized','Position',[0 0 1 1],...
'Data', defaultData,...
'ColumnName', columnname,...
'ColumnEditable', columneditable,...
'ColumnFormat', columnformat,...
'RowName',[],...
'CellEditCallback',@modifySelection,...
'CellSelectionCallback',@justifySelection);
set(h,'Tag','Config_figure')
set(t,'Tag','Config_table')
end
% **Appendix B**
% (part of the same function file)
function modifySelection(~,evt_edit)
if evt_edit.Indices(2) == 1
modifyPopup( evt_edit.Indices(1) );
end
end
function justifySelection(~,evt_select)
try %to surpress an unimportant error
if evt_select.Indices(2) == 2
modifyPopup( evt_select.Indices(1) );
end
end
end
最后是单个函数 modifyPopup
它重写了 Columnformat
:
function modifyPopup( row )
id_group_1 = {'A.1';'A.2';'A.3'};
id_group_2 = {'B.1';'B.2';'B.3'};
id_group_3 = {'C.1';'C.2';'C.3'};
id_default = {'select main option first'};
myfigure = findobj('Tag','Config_figure');
config_data = get(findobj(myfigure,'Tag','Config_table'),'Data');
selector = config_data(row,1);
selector = selector{1};
config_format = get(findobj(myfigure,'Tag','Config_table'),'ColumnFormat');
switch selector
case 'A'
config_format{2} = id_group_1';
case 'B'
config_format{2} = id_group_2';
case 'C'
config_format{2} = id_group_3';
otherwise
config_format{2} = id_default;
end
set(findobj(myfigure,'Tag','Config_table'),'ColumnFormat',config_format)
end
赏金:为什么只是 +50? - 我想这要么不可能,要么答案很简单,一旦有了正确的初步想法。我不是在寻找使用 Java 对象属性等的复杂解决方法。提前致谢!
我在这里包括评论中的讨论以保持概述:
如果您想尝试一下,可以复制代码并按照以下步骤重现不良行为:
- 选择第一行的主要选项A。
- 第一行的子选项包含选项 A.1、A.2 和 A.3.
- 选择第二行的主要选项 B,因此选择 第二行子选项为B.1、B.2、B.3
- 但是现在您想(直接)更改第一行中的子选项;你会期望得到选项 A.1、A.2 和 A.3;但你没有。您将获得 B.1、B.2 和 B.3; - 因为您选择的最后一个主要选项是 B(尽管在不同的行中)。
It seems that instead of looking for the last option, you should look at the relevant option. So either make sure that clicking on a suboption does a 'lookup' to see which main option there is,
Thats exactly what I'm looking for! But how could I do that? How to detect the click, get the column&row indices, set the right
ColumnFormat
and then finally let the cell pop up. The only possibility I see until now is theCellSelectionCallback
, but it is executed after the cell already popped up with the invalid choices. I'd need a kind ofClickedCallback
, like there is forpushbuttons
或者确保选择主选项只会设置该行的子选项。
那是不可能的,你不能为某一行设置子选项,因为你需要修改ColumnFormat
,这会影响整个表格,而不仅仅是一行。
最佳答案
我不会使用uitable
;它只是不适合这种事情。
这是我的做法:
function GUIdemo
%%// Construct GUI
%// Main figure
mainFig = figure;
set(mainFig, 'Color', get(0, 'DefaultUicontrolBackgroundColor'));
%// Create as many blocks as needed. The only thing you have to do is
%// figure out the "right" positions for each block
popupHandles = create_ui_blocks([
0.00 0.50 1.00 0.35
0.00 0.15 1.00 0.35]);
%// This OK button gathers all selected options, and just prints them.
uicontrol(...
'style' , 'pushbutton',...
'units' , 'normalized',...
'parent' , mainFig,...
'position', [0.4 0.01 0.2 0.1],...
'callback', @(~,~)getData(popupHandles),...
'string' , 'OK'...
);
%%// Helper functions
%// Create control blocks. Each block is composed of:
%// - a uipanel as container
%// - three radio buttons for the main selection
%// - a corresponding popup or the secondary selection
function popupHandles = create_ui_blocks(positions)
%// initialize
numBlocks = size(positions,1);
panels = zeros(numBlocks,1);
groups = zeros(numBlocks,1);
radios = zeros(numBlocks,3);
popups = zeros(numBlocks,1);
%// Build each block
for ii = 1:numBlocks
%// The container
panels(ii) = uipanel(...
'parent' , mainFig,...
'position', positions(ii,:)...
);
%// The radio buttons
groups(ii) = uibuttongroup(...
'parent' , panels(ii),...
'position', [0.05 0.05 0.45 0.9]...
);
radios(ii,1) = uicontrol(...
'style' , 'radio',...
'units' , 'normalized',...
'string' , 'A',...
'parent' , groups(ii),...
'position', [0.05 0.66 0.9 0.25]...
);
radios(ii,2) = uicontrol(...
'style' , 'radio',...
'units' , 'normalized',...
'string' , 'B',...
'parent' , groups(ii),...
'position', [0.05 0.33 0.9 0.25]...
);
radios(ii,3) = uicontrol(...
'style' , 'radio',...
'units' , 'normalized',...
'string' , 'C',...
'parent' , groups(ii),...
'position', [0.05 0.0 0.9 0.25]...
);
%// Initially, nothing's selected
set(groups(ii), 'SelectedObject',[]);
%// The popups
popups(ii) = uicontrol(...
'style' , 'popup',...
'units' , 'normalized',...
'parent' , panels(ii),...
'position', [0.55 0.4 0.4 0.2],...
'string' , 'Select main option',...
'enable' , 'off'...
);
%// On changing radiobutton, correct the string list of the popups
set(groups(ii),'SelectionChangeFcn', @(~,~)selectionChangeCallback(ii));
%// This is needed by the OK button callback
popupHandles = popups;
end
%// What happens when clicking a radio button?
%// NOTE: this is a doubly-nested function
function selectionChangeCallback(num)
switch get(groups(num), 'SelectedObject')
case radios(num,1)
set(popups(num), 'string', {'A.1', 'A.2', 'A.3'}, 'enable', 'on');
case radios(num,2)
set(popups(num), 'string', {'B.1', 'B.2', 'B.3'}, 'enable', 'on');
case radios(num,3)
set(popups(num), 'string', {'C.1', 'C.2', 'C.3'}, 'enable', 'on');
otherwise
%// ...
end
end
end
%// What happens when pressing the OK button?
function data = getData(popupHandles)
data = char(cellfun(@(x,y)x{y}, ...
get(popupHandles, 'String'),...
get(popupHandles, 'Value'),...
'UniformOutput', false)) %#ok<NOPRT> //
end
end
按下“确定”键时 MATLAB 命令窗口中的输出:
data =
A.1
B.1
布局当然还很粗糙,但你明白了。当然,单选按钮也可以替换为弹出窗口(更紧凑)、三个按钮或您喜欢的任何其他内容。
弹出窗口的内容彼此不相关,这正是 uitable
方法的问题。在此 GUI 中,当更改单选按钮时,弹出内容的更改可能是即时的,这仅仅是因为您可以更好地控制如何处理更改。
编程注意事项:我个人不喜欢我视为“ block ”的各个组件的句柄在顶层函数中 float ,这就是我使用双重嵌套函数的原因——它是有点像封装。现在,在课外使用时,这不是每个人都喜欢的,所以您可能想要转换它们。当然,所有嵌套函数都被简单地转换为子函数;您只需要手动传递更多信息。
使用这种方法,您将失去一些功能(调整 UI 元素大小的能力),但您获得 GUI 控件的直观行为。当这些是选择时,我已经接受过向后一种选择发展的训练。漂亮的花里胡哨只会在前几次给最终用户留下深刻印象,但随着使用量的增加,该程序的基本功能将变得越来越重要。正如您自己指出的那样,当您不得不经常使用该工具时,这种错误行为会变得烦人;我会说,放弃可调整大小以支持改进的控制行为。
关于matlab - 是否可以防止弹出合适的弹出菜单?或者 : How to get a callback by clicking a cell, 返回行和列索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19406767/