Я работаю над графическим интерфейсом (без GUIDE) в Matlab. Графический интерфейс в конечном итоге будет скомпилирован в приложение и выпущен моим сотрудникам.Matlab - Есть ли способ захватить сообщения, отправленные в рабочее пространство?
Мой GUI вызывает некоторые пользовательские функции, которые я написал много лет назад. Эти пользовательские функции отображают сообщения о статусе/ходе выполнения в окне рабочей области.
Как я понимаю, я мог иметь мой исполняемый писать эти сообщения в лог-файл, а затем, что оставляет пользователю без каких-либо обновлений статуса на GUI в то время как программа работает.
Я работаю над довольно интенсивными 3D-манипуляциями с данными, которые могут работать в течение 5-10 минут между вызовами функций, поэтому, хотя я мог бы предоставлять обновления статуса между вызовами функций, он все равно оставляет конечного пользователя без идея, что происходит и/или внешний вид, который программа заблокировала.
Что бы я хотел сделать, это иметь что-то похожее на метод 'try-catch', где я могу выполнить функцию и захватить сообщения, предназначенные для рабочей области, и перенаправить их в текстовое поле uicontrol.
: EDIT:
Я добавляю это для потомков, в том случае, кто хочет использовать его. Это функциональная демонстрация, которая показывает, как выполнить ответ Питера ниже.
Во-первых, создать и сохранить функцию под названием «EndlessLoop»:
function EndlessLoop(handles,loopCallback)
if nargin<1
handles = [];
loopCallback = @loop_Callback;
else
disp('Callback already set!');
end
tic;
abort = false;
while true
statusText = sprintf('Current Elapsed Time:\n%.2f',toc);
abort = loopCallback(handles,statusText);
if abort
statusText = sprintf('Abort request processed.\nEnding now.');
[~] = loopCallback(handles,statusText);
break;
end
pause(0.1);
end
return;
function abort = loop_Callback(~,myText)
clc;
abort = false;
disp(myText)
return;
Затем создать графический интерфейс, который вызывает на EndlessLoop:
function TestGUI
close all;
myTest = figure('Visible','on','Units','normalized','Position',[0.1 0.1 0.8 0.8],'Name','Test GUI','NumberTitle','off');
set(myTest,'menubar','none');
handles = guihandles(myTest);
handles.goButton = uicontrol('Style','pushbutton','Units','normalized','Position',[0 0.5 0.5 0.5],'String','Go');
handles.abortButton = uicontrol('Style','pushbutton','Units','normalized','Position',[0 0 0.5 0.5],'String','Abort','Enable','off');
handles.statusText = uicontrol('Style','text','Units','normalized','Position',[0.5 0 0.5 1],'String','Press Go when ready.');
set(handles.goButton,'Callback',@goButton_Callback,'interruptible','on');
set(handles.abortButton,'Callback',@abortButton_Callback,'interruptible','on');
handles.abortButton.UserData = false;
guidata(myTest,handles);
return;
function goButton_Callback(hObject,~)
handles = guidata(gcbo);
hObject.Enable = 'off';
handles.abortButton.Enable = 'on';
EndlessLoop(handles,@StatusUpdate)
handles.abortButton.String = 'Abort';
handles.abortButton.Enable = 'off';
hObject.Enable = 'on';
pause(0.5);
handles.statusText.String = 'Press Go to start again.';
handles.abortButton.UserData = false;
guidata(gcbo,handles);
return;
function abortButton_Callback(hObject,~)
handles = guidata(gcbo);
if handles.abortButton.UserData
handles.abortButton.UserData = false;
hObject.String = 'Abort';
else
handles.abortButton.UserData = true;
hObject.String = sprintf('Abort pending...');
end
guidata(gcbo,handles);
return;
function abort = StatusUpdate(handles,statusText)
clc;
abort = handles.abortButton.UserData;
disp(handles.abortButton.UserData)
handles.statusText.String = statusText;
return;
пару вещей, которые я нашел, когда играл с этим пытается чтобы получить его на работу:
Я просто добавляю переменные в структуру ручек для wh навсегда мне нужно. В этом случае это было бы
handles.abortRequest = false;
. Однако оказывается, что когда я передаюhandles
функции EndlessLoop, он становится устаревшим - ручки никогда не обновляются снова. Чтобы обойти это, мне пришлось хранить то, что я хотел в разделе UserData abortButton. Я думаю, что это потому, что дескриптор abortButton по-прежнему действителен, потому что он не изменился, и я получаю свежие UserData, потому что я могу опросить действительный дескриптор. Я не могу получить доступ к handles.abortRequest, потому что это не объект - я не могу опросить его; он просто существует и существует в «снимке», который был, когда я отправил дескрипторы в EndlessLoop. По крайней мере, это мое понимание.мне нужно установить
'Interruptible'
свойство обратного вызова goButton к'on'
, чтобы для abortButton функционировать в то время как процесс «висел» на EndlessLoop. Если Interruptible отключен, другие обратные вызовы могут быть обработаны до тех пор, пока этот конкретный обратный вызов не завершится, что никогда не произойдет с бесконечным циклом.
Итак, в заключение, это полный функциональный пример, который отвечает на мой вопрос. Спасибо Питеру за ответ - это также включает в себя его ProTip возможность передать вариант прерывания обратно в процесс, который занимает много времени. Я никогда не использовал обратные вызовы, подобные этому, поэтому, надеюсь, другие найдут это полезным в будущем.
['evalc'] (http://es.mathworks.com/help/matlab/ref/evalc.html)? –
Если вы можете изменить старые подпрограммы, вы можете разрешить им принимать функцию обратного вызова для обновлений состояния, которая по умолчанию будет отображаться в консоли, но может быть переопределена, чтобы быть функцией в вашем графическом интерфейсе. Если ваши подпрограммы могут определить приблизительный процентный коэффициент, поставьте его непосредственно на обратный вызов, чтобы графический интерфейс пользователя мог создать 'waitbar' – Peter
@Peter. Не могли бы вы рассказать подробнее? Я не совсем понимаю, что вы имеете в виду. Как мне настроить это? Я никогда не использовал обратные вызовы для функции, только для объектов uicontrol. – Chuck