Search code examples
matlabmatlab-guidetogglebutton

toggle button in Gui Matlab


I want to create a button which work as on/off switch: If the user pushes it, it starts counting and displays the counter on a static text. If the user pushes it again, it stops counting. Then, if the user pushes it for a third time, it continues counting.

I tried this code

function startStop_togglebutton_Callback(hObject, eventdata, handles)
% hObject    handle to startStop_togglebutton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of startStop_togglebutton

persistent counter ;

if isempty(counter)

    counter = 0 ;

end

button_state = get(hObject,'Value');

if button_state == get(hObject,'Max')

    set(handles.startStop_togglebutton,'String','Stop','ForegroundColor','red')

    setappdata(handles.startStop_togglebutton,'sw',1)

    while counter < 10

        counter = counter+1;

        set(handles.statusBar,'String',strcat(['the counter = ' num2str(counter) ]))

        pause(1)
    end

    set(handles.startStop_togglebutton,'String','Finished','ForegroundColor','cyan')
elseif button_state == get(hobject,'min')

    set(handles.startstop_togglebutton,'string','resume','foregroundcolor','blue')

    setappdata(handles.startstop_togglebutton,'sw',0)
    set(handles.statusBar,'String',strcat([' stopped & the counter = ' num2str(counter) ' !']))

end

but it doesn't work correctly: When I push the button for the first time, it starts counting and when I pushed it a second, time it's name changed but it was still counting.


Solution

  • In your present implementation of the counter, the while loop in the startStop_togglebutton callback is activated the first time you press the pushbuttonn to Start counting.

    It keeps running until the condition (counter < 10) holds even if you press again the ushbutton to Stop the counting.

    Therefore, to fix the problem you can use the value of the startStop_togglebutton insted of "1" to increment the counter.

    Below, you can find the updated version of the callback. I've also added a couple of "if" blocks to manage the displaying of the strings in the statusbar

    % --- Executes on button press in startStop_togglebutton.
    function startStop_togglebutton_Callback(hObject, eventdata, handles)
    % hObject    handle to startStop_togglebutton (see GCBO)
    % eventdata  reserved - to be defined in a future version of MATLAB
    % handles    structure with handles and user data (see GUIDATA)
    
    % Hint: get(hObject,'Value') returns toggle state of startStop_togglebutton
    
    % hObject    handle to startStop_togglebutton (see GCBO)
    % eventdata  reserved - to be defined in a future version of MATLAB
    % handles    structure with handles and user data (see GUIDATA)
    
    % Hint: get(hObject,'Value') returns toggle state of startStop_togglebutton
    
    persistent counter ;
    
    if isempty(counter)
    
        counter = 0 ;
    
    end
    
    button_state = get(hObject,'Value');
    
    if button_state == get(hObject,'Max')
    
        set(handles.startStop_togglebutton,'String','Stop','ForegroundColor','red')
    
        setappdata(handles.startStop_togglebutton,'sw',1)
    
        while counter < 10
    %
    % Inserted acquisition of button state within the while loop
    %
           button_state = get(hObject,'Value');
    %
    % Modified the counter increment:
    %    the increment is based on the status of the button
    %
    %        counter = counter+1;
           counter = counter+button_state;
    %
    % Added "if" condition
    %    The "statusbar" is updated only if counting is on
    %
           if(button_state)
               set(handles.statusBar,'String',strcat(['the counter = ' num2str(counter) ]))
           end
    
           pause(1)
        end
    
    %
    % Added "if" condition
    %    The "statusbar" is updatred only if counting is finished
    %
    if(counter == 10)
        set(handles.startStop_togglebutton,'String','Finished','ForegroundColor','cyan')
    end
    
    elseif button_state == get(hObject,'min')
    
        set(handles.startStop_togglebutton,'string','resume','foregroundcolor','blue')
    
        setappdata(handles.startStop_togglebutton,'sw',0)
        set(handles.statusBar,'String',strcat([' stopped & the counter = ' num2str(counter) ' !']))
    
    end
    

    UPDATING TO ANSWER TO THE COMMENT

    The reason for using the value of the togglebutton to increment the counter is the following.

    The first time you push the togglebutton to start the counter, the while loop is activated and the GUI is "waiting" for another callback regardless the loop is completed.

    Moreover the while loop has been coded into the if block that catches the Start / Continue action.

    This implies that when you push the togglebutton to stop the counter, the while loop is skipped.

    Getting the value of the togglebutton in the while loop allows to catch the change of the status of the button independently of the intended action (Stop / Restart).

    Indeed, when you push it to Stop the counter, the value is set to 0 so it does not increment the counter while when you push it to restart, its value is set to 1 and the counter is incremented.

    I suggest to model the counter GUI in a different way:

    • To code the counter in a separate ".m" file (or in a function)
    • To code in this ".m" file the logic for the increment of the counter (based on the value of the togglebutton)
    • To add a pushbutton which run the counter (the ".m" file)
    • To use the startStop_togglebutton callbach only to update the string displayed on the togglebutton

    The handling of the data between the GUI and the ".m" file is done by using the guidata function.

    The ".m". files identifies the GUI through its tag (in the code I've used to test the solution I've set the GUI figure tag as counter_gui).

    You should also set the property HandleVisibility of your GUI to 'on'

    In the following you can find:

    • the updated startStop_togglebutton callback, now very simple
    • the callback of the pushbutton used to start the counter
    • the ".m" file chich manages the counter

    startStop_togglebutton Callback

    % --- Executes on button press in startStop_togglebutton.
    function startStop_togglebutton_Callback(hObject, eventdata, handles)
    % hObject    handle to startStop_togglebutton (see GCBO)
    % eventdata  reserved - to be defined in a future version of MATLAB
    % handles    structure with handles and user data (see GUIDATA)
    
    % Hint: get(hObject,'Value') returns toggle state of startStop_togglebutton
    
    % hObject    handle to startStop_togglebutton (see GCBO)
    % eventdata  reserved - to be defined in a future version of MATLAB
    % handles    structure with handles and user data (see GUIDATA)
    
    % Hint: get(hObject,'Value') returns toggle state of startStop_togglebutton
    
    button_state = get(hObject,'Value');
    
    if(button_state == 1)
       set(handles.startStop_togglebutton,'String','Stop','ForegroundColor','red')
    else
        set(handles.startStop_togglebutton,'string','resume','foregroundcolor','blue')
    end
    

    run_counter callback

    % --- Executes on button press in run_counter.
    function run_counter_Callback(hObject, eventdata, handles)
    % hObject    handle to run_counter (see GCBO)
    % eventdata  reserved - to be defined in a future version of MATLAB
    % handles    structure with handles and user data (see GUIDATA)
    
    set(handles.startStop_togglebutton,'enable','on');
    set(handles.startStop_togglebutton,'Value',1);
    set(handles.run_counter,'enable','off');
    % Run the counter ".m" file
    run_counter;
    

    ".m" file managing the counter

    % Get tha handle of the GUI figure
    gui_h=findobj('tag','counter_gui');
    % Get gudata
    gui_my_data=guidata(gui_h);
    
    counter=0;
    while(counter < 10)
       % Get togglebutton value
       button_status=get(gui_my_data.startStop_togglebutton,'value');
       % Increment to counter only if the togglebutton is set to "Start/Resume"
       counter=counter+button_status;
       % Update strings
       if(button_status)
          set(gui_my_data.startStop_togglebutton,'String','Stop','ForegroundColor','red')
          set(gui_my_data.statusBar,'String',strcat(['the counter = ' num2str(counter) ]))
       else
          set(gui_my_data.statusBar,'String',strcat([' stopped & the counter = ' num2str(counter) ' !']))
       end
       pause(1);
    end
    
    set(gui_my_data.startStop_togglebutton,'String','Finished','ForegroundColor','cyan')
    set(gui_my_data.startStop_togglebutton,'enable','off');
    set(gui_my_data.run_counter,'enable','on');
    

    Hope this helps.