Остановить таймер Matlab из его обратного вызова (после внешнего ввода / события) - PullRequest
2 голосов
/ 17 апреля 2019

Я выполняю длинную предварительную загрузку данных в обратном вызове таймера, и я хотел бы иметь возможность остановить обратный вызов на полпути с помощью внешнего ввода (например, нажатием кнопки GUI).Функция stop() останавливает вызовы по таймеру, но не сама функция обратного вызова.

Вот простой пример:

timerh = timer('TimerFcn' , @TimerCallback,'StartDelay' , 1, 'ExecutionMode' , 'singleShot');
NeedStopping = false;

start(timerh)

disp('Running')
pause(1)
disp('Trying to stop')
NeedStopping = true;


function TimerCallback(obj, event)
% Background data loading in here code in here; in this example, 
% the callback simply displays numbers from 1 to 100

    for k = 1 : 100
        drawnow();  % Should allow Matlab to do other stuff
        NeedStopping = evalin('base' , 'NeedStopping');
        if NeedStopping
            disp('Should stop now')
            return
        end
        disp(k)
        pause(0.1)
    end
end

Я ожидаю, что этот скрипт будет отображать числа от 1 до (приблизительно) десять, но обратный вызов таймера не останавливается до 100. Как ни странно, код достигает строки непосредственно перед pause(1) и правильно печатает «Running», но затем останавливается и ожидает завершения таймера.Еще более озадачивает, если я изменю паузу в 1 секунду на 0,9 секунды, таймер немедленно остановится с таким выводом:

Запуск

Попытка остановить

Должен остановитьсясейчас

Я знаю, что Matlab в основном однопоточный, но я подумал, что функция drawnow() должна позволять обрабатывать другие вещи.


Редактировать: Специальное использованиеза моим вопросом: у меня есть графический интерфейс с кнопкой «Далее», которая загружает несколько изображений и показывает их все рядом.Изображения большие, поэтому загрузка занимает много времени;поэтому, пока пользователь смотрит на картинки, я хочу предварительно загрузить следующий набор.Это можно сделать в фоновом режиме с помощью таймера, и это работает.Однако, если пользователь нажимает «следующий» до завершения предварительной загрузки, мне нужно остановить его, показать текущие изображения и запустить предварительную загрузку для следующего шага.Следовательно, таймер должен остановиться во время выполнения обратного вызова.

1 Ответ

2 голосов
/ 17 апреля 2019

Это демонстрация того, как настроить прерывание callback. При настройке вашего примера я не видел необходимости в реальном таймере, поэтому я сделал это в качестве стандартного обратного вызова кнопки.

примечание: Если вы не можете использовать его для таймера, вы можете использовать точно такое же решение, просто назначьте обратный вызов startProcess для таймера вместо кнопки gui.

function h = interuptible_callback_demo

% generate basic gui with 2 buttons
h = create_gui ;
guidata( h.fig , h )

% create application data which will be used to interrupt the process
setappdata( h.fig , 'keepRunning' , true )

end


function startProcess(hobj,~)
    h = guidata( hobj ) ;
    % set the 'keepRunning' flag
    setappdata( h.fig , 'keepRunning' , true )
    % toggle the button states
    h.btnStart.Enable = 'off' ;
    h.btnStop.Enable  = 'on' ;

    nGrainOfSand = 1e6 ;
    for k=1:nGrainOfSand
        % first check if we have to keep running
        keepRunning = getappdata( h.fig , 'keepRunning' ) ;

        if keepRunning
            % This is where you do your lenghty stuff
            % we'll count grains of sand for this demo ...
            h.lbl.String = sprintf('Counting grains of sands: %d/%d',k,nGrainOfSand) ;
            pause(0.1) ;
        else
            % tidy up then bail out (=stop the callback)
            h.lbl.String = sprintf('Counting interrupted at: %d/%d',k,nGrainOfSand) ;
            % toggle the button states
            h.btnStart.Enable = 'on' ;
            h.btnStop.Enable = 'off' ;
            return
        end
    end
end

function stopProcess(hobj,~)
    h = guidata( hobj ) ;
    % modify the 'keepRunning' flag
    setappdata( h.fig , 'keepRunning' , false )
end

function h = create_gui
    h.fig = figure('units','pixel','Position',[200 200 350 200]) ;
    h.btnStart = uicontrol('style','pushbutton','string','Start process',...
                            'units','pixel','Position',[50 100 100 50],...
                            'Callback',@startProcess) ;
    h.btnStop  = uicontrol('style','pushbutton','string','Stop process',...
                            'units','pixel','Position',[200 100 100 50],...
                            'Callback',@stopProcess,'enable','off') ;
    h.lbl  = uicontrol('style','text','string','','units','pixel','Position',[50 20 200 50]) ;
end

Чтобы увидеть это в действии:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...