14

I am working in a GUI in MATLAB and I use tabs to organize the information. As the tabs are not supported in MATLAB GUIDE, I just create several uipanels and change their 'Visible' field. However, when the number of controls within each panel is large, it takes some time to switch between panels. Does anybody know a way to make tab switching faster?

I include a simple example of the tab-based interface.

tab_example_gui.m

% Figure
handles.figure_window = figure(...
    'Units','characters',...
    'Tag','figure_window',...
    'Position',[50 50 80 25],...
    'Name','Tab Example',...
    'DockControls','off',...
    'IntegerHandle','off',...
    'MenuBar','none',...
    'NumberTitle','off',...
    'Resize','off');

% Buttons
handles.tab_panel = uibuttongroup(...
    'Parent',handles.figure_window,...
    'Tag','tab_panel',...
    'Units','characters',...
    'Position',[0 23 80 2],...
    'SelectionChangeFcn',@(hObject,eventdata)tab_example_callback(hObject,eventdata,guidata(hObject)),...
    'BorderType','none');
handles.tab_a = uicontrol(...
    'Parent',handles.tab_panel,...
    'Tag','tab_a',...
    'Units','characters',...
    'Position',[0 0 40 2],...
    'Style','togglebutton',...
    'String','Tab A');
handles.tab_b = uicontrol(...
    'Parent',handles.tab_panel,...
    'Tag','tab_b',...
    'Units','characters',...
    'Position',[40 0 40 2],...
    'Style','togglebutton',...
    'String','Tab B');


% Panel A
handles.panel_a = uipanel(...
    'Parent',handles.figure_window,...
    'Tag','panel_menu',...
    'Units','characters',...
    'Position',[0.1 0 79.8 23],...
    'Visible','On');
handles.panel_a_text = uicontrol(...
    'Parent',handles.panel_a,...
    'Tag','panel_menu_load_id_text',...
    'Units','characters',...
    'Position',[0 0 77 22],...
    'Style','text',...
    'String','This is the tab A');

% Panel B
handles.panel_b = uipanel(...
    'Parent',handles.figure_window,...
    'Tag','panel_menu',...
    'Units','characters',...
    'Position',[0.1 0 79.8 23],...
    'Visible','Off');
handles.panel_b_text = uicontrol(...
    'Parent',handles.panel_b,...
    'Tag','panel_menu_load_id_text',...
    'Units','characters',...
    'Position',[0 0 77 22],...
    'Style','text',...
    'String','This is the tab B');

guidata(handles.figure_window, handles);

tab_example_callback.m

function tab_example_callback(hObject,eventdata,handles)
    switch get(get(hObject,'SelectedObject'),'Tag')
        case 'tab_a', set(handles.panel_a,'Visible','On'); set(handles.panel_b,'Visible','Off');
        case 'tab_b', set(handles.panel_a,'Visible','Off'); set(handles.panel_b,'Visible','On');
    end
    guidata(handles.figure_window, handles);
end

Note: The GUI is to introduce parameters for a simulation in 5 tabs. In each tab, I have around 15 rows; and each row has one text, one checkbox and three edits. It does not look overcrowded for me. Besides, I have made the layout and callbacks on my own with the minimum amount of code and overhead. But, it still has very annoying tab transitions.

tashuhka
  • 5,028
  • 4
  • 45
  • 64
  • 1
    I was thinking that all the panels can be visible, but their location is placed outside of the main figure. Thus, when a tab is selected, the old tab is moved away and the new one is brought. In this way, maybe all the panels are cached in the GPU memory and the transitions are faster... – tashuhka Feb 06 '13 at 09:37
  • 1
    I think that the defaults values for rendering are fast enough, i.e. 'DoubleBuffer','on','Renderer', 'painters','RendererMode', 'auto'. Any other combination that could be faster? – tashuhka Feb 07 '13 at 08:59
  • I have tried to use 'Position' instead of 'Visible' as the parameter that switches among tabs, but I couldn't appreciate any improvement. I have also tried different rendering combinations with the same result. – tashuhka Feb 07 '13 at 09:12
  • Have not tried it myself, but perhaps it would help if you did not use multiple panels, but just one and change the visibility of the content? – Dennis Jaheruddin Feb 07 '13 at 09:35
  • Thank you for the reply. I gave it a try, but unfortunately it did not make it better.I guess the actual problem is to propagate the update of the 'Visible' property through lot of objects. – tashuhka Feb 07 '13 at 10:11
  • Perhaps the comments posted by Yair Altman could be of help: http://blogs.mathworks.com/community/2010/02/15/putting-the-tab-into-a-gui/ – Dennis Jaheruddin Feb 07 '13 at 10:20
  • Thank you for the suggestion. The idea behind my code is exactly the same than the Yair's one. The difference is than each of my panels has more than 50 controls, which makes slow the transitions. – tashuhka Feb 07 '13 at 14:12
  • I have also tried with uistack(), but the uicontrol's of the previous tab are not removed. – tashuhka Feb 18 '13 at 14:30

3 Answers3

3

Maybe if you put the handles in an array. That way you do not have to go through each one of them. This seems fast to me, but 'fast' can mean a lot of things :)

I removed some of the properties to make the example shorter...

function test(N) % N is the number of tabs
if nargin == 0
    N = 3;
end

% Figure
handles.figure_window = figure(...
    'Units','characters',...
    'Position',[50 50 80 25]);
% Buttons
handles.tab_panel = uibuttongroup(...
    'Parent',handles.figure_window,...
    'Units','characters',...
    'Position',[0 23 80 2]);

alpha = 'ABCDEFGHIJKLMNOPQRSTUVXYZ';
for i_tab=1:N
    % button
    handles.tabs(i_tab) = uicontrol(...
        'Parent',handles.tab_panel,...
        'Units','characters',...
        'Position',[80/N*(i_tab-1) 0 80/N 2],...
        'Style','togglebutton',...
        'String',['Tab ' alpha(i_tab)]);

    % Panel i
    handles.panels(i_tab) = uipanel(...
        'Parent',handles.figure_window,...
        'Units','characters',...
        'Position',[0.1 0 79.8 23],...
        'Visible','Off');
    handles.panel_a_text = uicontrol(...
        'Parent',handles.panels(i_tab),...
        'Units','characters',...
        'Position',[0 0 77 22],...
        'Style','text',...
        'String',['This is the tab ', alpha(i_tab)]);
end
% set callback for all buttons
set(handles.tabs, 'callback', {@tab_example_callback  handles})
% choose tab 1 as active
set(handles.panels(1), 'Visible','On');
guidata(handles.figure_window, handles);

function tab_example_callback(hObject,eventdata,handles)
% set everything invisible
set(handles.panels,'Visible','Off');
% turn on selected panel
set(handles.panels(handles.tabs == hObject), 'Visible','On');
guidata(handles.figure_window, handles);

Does that help you out?

  • 1
    That's an interesting idea. The Profiler actually shows a slightly better computation time. Unfortunately, it is not significant enough for the human eye perception. But thank you for your time and code, it seems pretty neat and gave some good ideas to improve my coding :) – tashuhka Mar 18 '13 at 09:34
2

I strongly recommend that if you are creating a GUI of any complexity, you take a look at GUI Layout Toolbox, and do not use GUIDE - it's just not fit for purpose when creating complex GUIs (that's not a criticism, it's just that it's only designed for making quick, simple GUIs).

GUI Layout Toolbox makes it vastly easier to create professional-standard GUIs, and includes functionality for tabs, as well as much else such as easy resizing and additional widgets.

To address some of the concerns you raised in comments to other answers. GUI Layout Toolbox uses no undocumented / unsupported / hidden features of MATLAB. Although it's not an official MathWorks product, it's developed by Ben Tordoff and David Sampson from MathWorks consulting group, and is freely available under a license that means it's fine for you to use and include in a deployed product.

As a side note, you mention in one comment that your tabs each include about 50 controls. I wonder whether the real solution might be to redesign your GUI a bit? Of course, you would know better then me what is appropriate for your application, but 50 controls visible to the user at once seems like it might be a bad idea from a usability perspective, as well as presenting difficulties for GUI redraw times.

Sam Roberts
  • 23,951
  • 1
  • 40
  • 64
  • Thank you for your detailed reply, @Sam Roberts. I had a look at the GUI Layout Toolbox, and it's indeed amazing the great work that they did. In the file *CardPanel.m*, it is included the function *showSelectedChild* that handles the visibility of the tabs. They change the position of tabs by shifting 2500 pixels away the not-visible panels. I have tried this option in the past, and the flickering and freezing is still there. – tashuhka Mar 13 '14 at 12:52
  • BTW, I totally agree with you that GUIDE is not useful for complex GUI's. In fact, I write the layout myself in order to have control over all the modules. – tashuhka Mar 13 '14 at 12:54
  • 3
    I think some flickering, or a lack of GUI responsiveness may be inevitable if you have ~50 controls on a panel. I have previously got around a similar situation by disabling all children of a panel, making the transition, adding a `pause(0.5)`, and then re-enabling the children. There's a delay, but no flickering, and I've found that people find it a bit more acceptable because the disabling causes a graying of the controls, so they "know what's happening". If it's really bad, you can also use a bit of Java to change the cursor to a spinner temporarily. – Sam Roberts Mar 13 '14 at 13:03
  • Thank you @Sam Roberts. I already had a `pause(0.1)`. The `pause()` makes the transitions cleaner. But, this is just a nice makeup, I am curious if there is any implementation that can make the tab transitions faster. Nowadays, waiting 1 second to have all the fields visible while switching tabs in a simple desktop application seems excessive. – tashuhka Mar 13 '14 at 15:11
  • 1
    Wow, big +1. The lack of real layout controls in Matlab's handle graphics is a big limitation. If I had known about this toolbox before it would have saved me some real headaches over the years. Also, you shouldn't need Java to change the cursor: if you `set(h, `Pointer`, 'watch')` on your figure handle, it will change the cursor to a system-appropriate busy indicator, like the Mac spinner or Windows hourglass. – Andrew Janke Mar 16 '14 at 00:24
1

If you're free to use undocumented features, I suggest using uitab or tabdlg. See this post on undocumentedmatlab.com.

Sam Roberts
  • 23,951
  • 1
  • 40
  • 64
Florian Brucker
  • 9,621
  • 3
  • 48
  • 81
  • 1
    Thank you for the suggestion. It seems that Mathworks is actually working on tabs, which is terrific. Unfortunately, I cannot deploy code, which probably will not be functional in the close future. – tashuhka Mar 18 '13 at 09:27