是否可以防止弹出一个合适的弹出菜单?或者:如何通过单击单元格获得回调,返回行 &列索引? [英] Is it possible to prevent an uitable popup menu from popping up? Or: How to get a callback by clicking a cell, returning the row & column index?

查看:13
本文介绍了是否可以防止弹出一个合适的弹出菜单?或者:如何通过单击单元格获得回调,返回行 &列索引?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于用户界面,我正在编写uitable.用户在第一列中选​​择选项 A、B 或 C,第二列中的子选项取决于在第一列中选​​择的内容,A.1、A.2 或 A.3B.1、B.2 或 B.3C

相同

表格的代码可以在附录 A 中找到.

当用户第一次定义主选项时,子选项会自动相应地减少到只有有效的选项.这是通过评估第 1 列的 CellEditCallback 并重置第 2 列的 ColumnFormat 来实现的.(附录 B 中的函数 modifySelection强>)如果用户现在意识到自己犯了一个错误,需要再次编辑子选项,那么 ColumnFormat 仍然按照之前编辑的主选项设置,有效选项不可用,除非他重新选择另一个时间的主要选择.(参见图片中的蓝色突出显示).

为了解决这个问题,我还实现了CellSelectionCallback调用函数justifySelection(在附录B中),它通过选择进行检查,在第 1 列中选择了选项以再次为第 2 列提供正确的子选项.但是当此回调对选择做出反应时,我需要选择 两次,一次触发 CellSelectionCallback另一个是真正得到我的选择.对于大表,这可能会很烦人!

所以我的问题是:

有没有办法防止第2列的弹出菜单弹出,直到它找出对应的第1列的内容,然后立即提供有效的选择?

或者:

如何检测到鼠标在单元格上的点击并获取行和列索引?但是没有调用以下选择和弹出操作?

我已经收集了所有可用属性但没有发现任何有用的东西.也许可以使用 ButtonDownFcn 做一些事情,但是如何获取单元格索引?BusyAction 属性怎么样,它如何用于我的目的?

有什么想法吗?

我很抱歉提前用这么多代码轰炸你,它已经是最小的例子,但完全可执行,所以你可以尝试一下.

<小时>

附录 A/B

函数fancyUitable选择器_1 = {'A';'乙';'C' };selector_2 = { '先选择第一行!'};h = figure('Position',[200 100 268 120],'numbertitle','off','MenuBar','none');defaultData = repmat( {'选择主选项...', '选择子选项...'} ,5,1);列名 = {'选项',...'子选项'};columnformat = { {selector_1{:}}, selector_2 };columneditable = [真真];t = uitable(h,'Units','normalized','Position',[0 0 1 1],...'数据',默认数据,...'列名',列名,...'ColumnEditable', columneditable,...'ColumnFormat', columnformat,...'行名',[],...'CellEditCallback',@modifySelection,...'CellSelectionCallback',@justifySelection);set(h,'Tag','Config_figure')set(t,'Tag','Config_table')结尾% **附录 B**%(同一函数文件的一部分)函数修改选择(~,evt_edit)如果 evt_edit.Indices(2) == 1modifyPopup(evt_edit.Indices(1));结尾结尾函数 justifySelection(~,evt_select)尝试 % 抑制一个不重要的错误如果 evt_select.Indices(2) == 2modifyPopup(evt_select.Indices(1));结尾结尾结尾

<小时>

最后是重写Columnformat的单个函数modifyPopup:

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 = {'先选择主选项'};myfigure = findobj('Tag','Config_figure');config_data = get(findobj(myfigure,'Tag','Config_table'),'Data');选择器 = config_data(row,1);选择器 = 选择器{1};config_format = get(findobj(myfigure,'Tag','Config_table'),'ColumnFormat');开关选择器案例A"config_format{2} = id_group_1';案例B"config_format{2} = id_group_2';案例C"config_format{2} = id_group_3';否则config_format{2} = id_default;结尾set(findobj(myfigure,'Tag','Config_table'),'ColumnFormat',config_format)结尾

赏金:为什么只是+50?- 我想这是不可能的,或者答案很简单,一旦有了正确的初步想法.我不是在寻找使用 java 对象属性等的复杂解决方法.在此先感谢您!

<小时>

我在此处包含评论中的讨论以保持概述:

如果您想尝试一下,可以复制代码并按照以下步骤重现不良行为:

  1. 在第一行选择主要选项 A.
  2. 第一行中的子选项包含选项 A.1、A.2 和A.3.
  3. 在第二行选择主要选项 B,因此选择第二行的子选项是B.1、B.2和B.3
  4. 但现在您想更改第一行中的子选项(直接);你会期望得到选项 A.1、A.2 和 A.3;但你没有.您获得 B.1、B.2 和B.3;- 因为您选择的最后一个主要选项是 B(尽管在不同的行中).

<块引用>

看来与其找最后一个选项,不如看看相关的选项.所以要么确保点击一个子选项进行查找"以查看存在哪个主要选项,

这正是我要找的!但我怎么能这样做呢?如何检测点击,获取列和行索引,设置正确ColumnFormat 然后最后让单元格弹出.到目前为止,我看到的可能性是 CellSelectionCallback,但它是在单元格弹出无效选项后执行.我需要一种 ClickedCallback,就像 pushbuttons

或者确保选择主选项只会设置该行的子选项.

那不可能,你不能为某一行设置子选项,因为你需要修改ColumnFormat,这会影响整个表格,而不仅仅是一行.

解决方案

虽然我非常感谢 Rody Oldenhuis 的努力和解决方案,他绝对配得上这个奖项,但他的解决方案需要对我的代码进行大量更改,所以我一直试图找到一个更简单的解决方案.在这里,终于 99% 没有错误了.

(函数脚本中的所有代码部分)

函数fancyUitable关闭所有%基本属性线高度 = 21.32;table_height = 6*line_height;lh = line_height/table_height;顺 = 200;%列宽h = figure('位置',[200 100 2*cw+2 table_height],...'numbertitle','off','MenuBar','none');%标题uitable(h,'Units','normalized','Position',[0 1-lh 1 lh],...'ColumnWidth', {cw cw},...'ColumnName', {'Option','Suboption'},...'行名',[]);%button(目前没有图标)来存储表格tbar = uitoolbar(h);uipushtool(tbar,'ClickedCallback',@store);% addrow(图形句柄,行数,行高百分比)% 每个函数调用创建一个新行,稍后动态addRow(h,1,lh);addRow(h,2,lh);addRow(h,3,lh);addRow(h,4,lh);addRow(h,5,lh);结尾

<小时>

函数编辑(src,evt)如果 evt.Indices(2) == 1modifyPopup(src,evt.Indices(1));结尾% 禁用单元格选择突出显示,当跳转到下一个表格时,% 虽然有点滞后fh = get(src,'parent');copyobj(src,fh);删除(源代码);结尾函数 modifyPopup( src,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 = {'先选择输出文件'};config_data = get(src,'数据');选择器 = config_data(row,1);选择器 = 选择器{1};config_format = get(src,'ColumnFormat');开关选择器案例A"config_format{2} = id_group_1';案例B"config_format{2} = id_group_2';案例C"config_format{2} = id_group_3';否则config_format{2} = id_default;结尾config_data = { 选择器,'选择子选项...' };%重置第 2 列设置(src,'数据',配置数据);set(src,'ColumnFormat',config_format);结尾

<小时>

function addRow(fh,k,lhp)选择器_1 = {'A';'乙';'C' };selector_2 = { '先选择第一行!'};defaultData = {'选择主选项...', '选择子选项...'};columnformat = { {selector_1{:}}, selector_2};columneditable = [真真];th = uitable(fh,'Units','normalized','Position',[0 1-(k+1)*lhp 1 lhp],...'数据',默认数据,...'列名', [],...'列宽', {200 200},...'ColumnEditable', columneditable,...'ColumnFormat', columnformat,...'行名',[],...'标签','值',...'用户数据',k,...'选择突出显示','关闭',...'CellEditCallback',@edit);结尾

<小时>

函数存储(~,~)ui = findobj(0,'Type','uitable','Tag','value');L = numel(ui);输出=单元格(L,2);订单=零(L,1);对于 ii=1:L;output(ii,:) = get(ui(ii),'Data');order(ii) = get(ui(ii),'UserData');结尾[~,idx] = 排序(顺序);%as 句柄顺序不等于显示顺序assignin('base','output',output(idx,:));结尾

提出:

For an user interface I'm programming an uitable. The user chooses an option A,B or C in the first column and the suboption in the second column depends on what was chosen in the first, either A.1,A.2 or A.3 or B.1,B.2 or B.3 or the same for C

The code for the table can be found in Appendix A.

When the user first defines the main option, then automatically the suboptions are reduced accordingly to only valid choices. This is realized by evalulating the CellEditCallback for column 1 and resetting the ColumnFormat for column 2. (function modifySelection in Appendix B) If the user now realizes he made a mistake and needs to edit a suboption another time, then the ColumnFormat is still set according to the previous edited main option and the valid choices are not available unless he re-chooes the main option another time. (see the blue highlighting in picture).

To resolve this, I also implemented the CellSelectionCallback calling the function justifySelection (in Appendix B), which is checking by selection, which option was chosen in column 1 to offer again the right suboptions for column 2. But as this callback reacts on selection, I need to select twice, one time to trigger the CellSelectionCallback and another to actually get my choices. For large tables, this can be very annoying!

So my question is:

Is there a way to prevent the popup menu in column 2 from popping up, until it found out what's the content of the according column 1, so it immediately offers the valid choices?

Or:

How could I detect a mouse click on a cell and get the row and column-index? But without invoking the following selection and popping up action?

I was already raking all available properties but didn't found anything which could be useful. Maybe one could do something using the ButtonDownFcn, but how to get the cell indices? What about the BusyAction property, how can that be used for my purpose?

Any ideas?

I'm sorry in advance to bomb you with so much code, it's already the most minimal example, but fully executable, so you can try it out.


Appendix 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


and finally the single function modifyPopup which rewrites the 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

Bounty: Why just +50? - I guess it's either not possible or the answer is easy, once one had the right initial idea. I'm not looking a for a complex workaround using java object properties etc. Thank you in advance!


I include the discussion from the comments here to keep the overview:

If you want to try it out, you can copy the code and follow these steps to reproduce the undesired behaviour:

  1. select main option A in the first row.
  2. the suboption in the first row then contains the choices A.1, A.2 and A.3.
  3. select main option B in the second row, therefore the choices for the suboption in the second row are B.1, B.2 and B.3
  4. BUT NOW you want to change the suboption in the first row (directly); you would expect to get the choices A.1, A.2 and A.3; but you don't. You get offered B.1, B.2 & B.3; - Because the last main option you selected was B (though in a diffrent row).

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 the CellSelectionCallback, but it is executed after the cell already popped up with the invalid choices. I'd need a kind of ClickedCallback, like there is for pushbuttons

or make sure that selecting a main option only sets the suboptions for that row.

That's not possible, you can't set a suboption for a certain row as you need to modify ColumnFormat, which affects the whole table and not just one row.

解决方案

Though I highly appreciate the effort and the solution of Rody Oldenhuis and he definetely deserved the award, his solution would have required a lot of changes in my code, so I kept trying to find a simpler solution. Here it is, finally 99% bug-free.

(all code parts within on function script)

function fancyUitable 

close all

%basic properties
line_height = 21.32;
table_height = 6*line_height;
lh = line_height/table_height;
cw = 200; %columnwidth

h = figure('Position',[200 100 2*cw+2 table_height],...
           'numbertitle','off','MenuBar','none');

%header
uitable(h,'Units','normalized','Position',[0 1-lh 1 lh],...
              'ColumnWidth', {cw cw},...              
              'ColumnName', {'Option','Suboption'},...
              'RowName',[]);

%button (currently no icon) to store table
tbar = uitoolbar(h);
uipushtool(tbar,'ClickedCallback',@store);

% addrow(figurehandle,number of row, percentage lineheight)
% every function call creates a new row, later dynamically
addRow(h,1,lh);
addRow(h,2,lh);
addRow(h,3,lh);
addRow(h,4,lh);
addRow(h,5,lh);
end


function edit(src,evt)

if evt.Indices(2) == 1
    modifyPopup( src,evt.Indices(1) );
end

% disables cell selection highlighting, when one jumps to next table,
% a bit laggy though
fh = get(src,'parent');
copyobj(src,fh);
delete(src);

end

function  modifyPopup( src,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 output file first'};

    config_data = get(src,'Data');
    selector = config_data(row,1);
    selector = selector{1};

    config_format = get(src,'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
    config_data = { selector , 'select suboption...' };  %reset column 2
    set(src,'Data',config_data);
    set(src,'ColumnFormat',config_format);
end


function addRow(fh,k,lhp)
selector_1 = { 'A'; 'B' ; 'C' };
selector_2 = { 'first select first row!' };

defaultData =  {'select main option...', 'select suboption...'};
columnformat = { {selector_1{:}}, selector_2};
columneditable =  [true true];

th = uitable(fh,'Units','normalized','Position',[0 1-(k+1)*lhp 1 lhp],...
              'Data', defaultData,... 
              'ColumnName', [],...
              'ColumnWidth', {200 200},...
              'ColumnEditable', columneditable,...
              'ColumnFormat', columnformat,...  
              'RowName',[],...
              'Tag','value',...
              'UserData',k,...
              'SelectionHighlight','off',...
              'CellEditCallback',@edit);
end


function store(~,~)
ui = findobj(0,'Type','uitable','Tag','value');
L = numel(ui);
output = cell(L,2);
order = zeros(L,1);
for ii=1:L;
    output(ii,:) = get(ui(ii),'Data');
    order(ii)    = get(ui(ii),'UserData');
end
[~,idx] = sort(order);    %as order of handles unequals displayed order
assignin('base','output',output(idx,:));
end

brings up:

这篇关于是否可以防止弹出一个合适的弹出菜单?或者:如何通过单击单元格获得回调,返回行 &amp;列索引?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆