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?

后端 未结 3 637
悲哀的现实
悲哀的现实 2020-12-10 16:15

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 colu

3条回答
  •  失恋的感觉
    2020-12-10 16:56

    I would not use a uitable; it's just not suited for this sort of thing.

    Here's how I would do it:

    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 //
        end
    
    end
    

    enter image description here enter image description here

    Output in the MATLAB command window when pressing "OK":

    data =
        A.1
        B.1
    

    The layout is of course still crude, but you get the idea. Of course, the radio buttons can also be replaced by a popup (more compact), three pushbuttons, or whatever else you like.

    The contents of the popups are not related to each other, which is exactly the problem with the uitable approach. In this GUI, changes in the popup's contents can be instantaneous when changing a radio button, simply because you have better control over how to deal with changes.

    A programming note: I personally don't like it when handles of individual components in what I treat as a "block" are floating around in the top-level function, which is why I use doubly-nested functions -- it's kind of like encapsulation. Now, when used outside of classes, this is not everyone's cup of tea, so you might want to convert them. Of course, all nested functions are trivially converted to subfunctions; you just have to manually pass a lot more information around.

    With this approach, you lose some functionality (the ability to re-size your UI elements), but you gain intuitive behavior of the GUI controls. When these are the choices, I've been trained to develop towards the latter option. The nice bells and whistles will only impress the end-user the first few times round, but the program's basic functionality will become more and more important with increased usage. As you noted yourself, this buggy behavior gets annoying when you have to use the tool a lot; I'd say, drop the resizability in favor of improved control behavior.

提交回复
热议问题