Matlab - отображать вывод команды dos в статический текст

я использую графический интерфейс для вызова команды терминала. Используя dos(my_command, '-echo'), я могу получить вывод команды в командном окне Matlab. Есть ли способ воспроизвести этот -echo в статическом тексте в моем графическом интерфейсе?

В настоящее время с my_command я записываю вывод в файл log и обновляю строку статического текста этим файлом log после завершения процесса, но я хочу live-view, как в командном окне: вывод отображается построчно в режиме реального времени. . Спасибо.

Обновлять:

@Hoki: еще один вопрос: когда выполняются консольные команды, если я закрываю графический интерфейс, тогда Matlab возвращает неудержимые ошибки, как я могу заморозить весь графический интерфейс, пока команды не будут выполнены?

введите здесь описание изображения


person scmg    schedule 09.07.2015    source источник
comment
Здесь был задан дополнительный вопрос: stackoverflow. ком/вопросы/38478641/   -  person Dennis Jaheruddin    schedule 20.07.2016


Ответы (2)


Благодаря информации Яира Альтмана в этой статье , у меня есть кое-что для работы, но это связано с взломом базовых объектов Matlab Java (а именно, командного окна).

commandWindowGui

Он включает в себя присоединение слушателя к командному окну Matlab. Теперь будьте осторожны, часто сохраняйте свою работу и будьте готовы остановить процесс Matlab довольно много раз, пока вы не сделаете это правильно ... потому что каждый раз, когда у вас есть ошибка в коде, вы застреваете в своего рода бесконечном цикле (ошибка/ предупреждение отправляется в командное окно, которое запускает ваш прослушиватель, который повторно запускает ошибку и т. д.). Мне пришлось перезапускать Matlab добрую дюжину раз только для того, чтобы приведенный ниже пример работал стабильно.

Это также причина, по которой я только временно подключаю слушателя. непосредственно перед отправкой команды dos, и сразу после этого я удаляю прослушиватель. Вы можете оставить слушателя навсегда или настроить его под свои нужды, но помните совет, приведенный чуть выше. Также учтите, что командное окно может содержать огромное количество символов, которые вам могут не понадобиться в вашем текстовом поле, поэтому вам нужно управлять текстом, который вы получаете из него (взять подмножество, как в примере), и подумать, если вы хотите добавить или просто обновить текст в текстовом поле.

Пример ниже кажется стабильным, любые изменения на свой страх и риск ;-)

После запроса в комментарии я добавил 3 функции:

  • onCleanup. Это функция Matlab, позволяющая действовать в крайнем случае в случае, если что-то пойдет не так (своего рода механизм «уловить все»). Настоятельно рекомендуется для такого рода программ, использующих недокументированные функции.

  • myCloseRequestFcn, которые перехватывают действие закрытия окна, чтобы удалить прослушиватель и избежать циклов ошибок.

  • Функция scroll_to_bottom. Это позволяет переместить курсор текстового поля в конец текста (= прокрутить вниз, если текста больше, чем видимого пространства).

Предупреждение. Последняя функциональность может заслуживать отдельного вопроса и снова требовать недокументированной функциональности (поэтому совместимость никогда не гарантируется). Чтобы реализовать его, вам необходимо иметь findjobj доступна в вашем пути к Matlab. Если вы не хотите загружать внешний компонент, то удалите/закомментируйте часть кода, которая использует его и подфункцию scroll_to_bottom (и забудьте о прокрутке текстового поля, в чистом Matlab этого сделать нельзя). Или вы можете выбрать предыдущую версию кода, просмотрев историю редактирования сообщения.


function h = gui_MirrorCmdWindow

%% // just to remove the listener in case something goes wrong
closeup = onCleanup(@() cleanup);

%% // create figure and uicontrol
h.f = figure;
h.txtOut = uicontrol(h.f,'Style','edit','Max',30,'Min',0,...
                   'HorizontalAlignment','left',...
                   'FontName','FixedWidth',...
                   'Units','Normalized',...
                   'Enable','On',...
                   'Position',[.05 .2 .9 .75]);

h.btnPing = uicontrol(h.f,'Style','Pushbutton',...
                   'String','Ping',...
                   'Units','Normalized',...
                   'Position',[.05 .05 .9 .1],...
                   'Callback',@btnPing_callback);

guidata(h.f,h)

%// intercept close request function to cleanup before close
set(gcf,'CloseRequestFcn',@myCloseRequestFcn) 

%% // Get the handle of the Matlab control window
jDesktop = com.mathworks.mde.desk.MLDesktop.getInstance;
jCmdWin = jDesktop.getClient('Command Window');
jTextArea = jCmdWin.getComponent(0).getViewport.getView;

%% // Get the handle of the jave edit box panel component
jtxtBox = findjobj(h.txtOut) ;
jTxtPane = jtxtBox.getComponent(0).getComponent(0) ;

%// Save these handles
setappdata( h.f , 'jTextArea', jTextArea ) ;
setappdata( h.f , 'jTxtPane',  jTxtPane ) ;


function btnPing_callback(hobj,~)
    h = guidata(hobj) ;
    jTextArea = getappdata( h.f , 'jTextArea' ) ;

    my_command = 'ping google.com -n 10' ;
    startPos = jTextArea.getCaretPosition ;
    set(jTextArea,'CaretUpdateCallback',{@commandWindowMirror,h.f,startPos}) ;
    dos( my_command , '-echo' ) ;
    pause(1) %// just to make sure we catch the last ECHO before we kill the callback
    set(jTextArea,'CaretUpdateCallback',[]) ;
    scroll_to_bottom(h.f)


function commandWindowMirror(~,~,hf,startPos)
    h = guidata(hf) ;
    jTextArea = getappdata( h.f , 'jTextArea' ) ;

    %// retrieve the text since the start position
    txtLength = jTextArea.getCaretPosition-startPos ;
    if txtLength > 0 %// in case a smart bugger pulled a 'clc' between calls
        cwText = char(jTextArea.getText(startPos-1,txtLength) ) ; 
    end
    %// display it in the gui textbox
    set( h.txtOut, 'String',cwText ) ; 
    scroll_to_bottom(h.f)


function scroll_to_bottom(hf)
    %// place caret at the end of the texbox (=scroll to bottom)
    jTxtPane  = getappdata( hf , 'jTxtPane' ) ;
    jTxtPane.setCaretPosition(jTxtPane.getDocument.getLength)


function myCloseRequestFcn(hobj,~)
    cleanup ;       %// make sure we remove the listener
    delete(hobj) ;  %// delete the figure


function cleanup
    jDesktop = com.mathworks.mde.desk.MLDesktop.getInstance;
    jCmdWin = jDesktop.getClient('Command Window');
    jTextArea = jCmdWin.getComponent(0).getViewport.getView;
    set(jTextArea,'CaretUpdateCallback',[]) ;
person Hoki    schedule 09.07.2015
comment
я попытаюсь сначала смешать это с моим графическим интерфейсом и вернуться - person scmg; 09.07.2015
comment
я попробовал, и все еще есть вопрос: если журнал слишком длинный, как я могу установить позицию текста в конце? - person scmg; 09.07.2015
comment
@scmg. Я не понимаю вашего вопроса. Вы имеете в виду установить начальную позицию копии в конце командного окна? - person Hoki; 09.07.2015
comment
нет, я имею в виду: если вывод в DOS слишком длинный, текстовое поле всегда показывает первую часть журнала, как я могу заставить его отображать последнюю часть журнала, как на картинке, которую я обновил? вопрос? - person scmg; 09.07.2015
comment
я использовал ваш пример и вызывал DOS 3 раза, поэтому вывод превышает высоту текстового поля, затем появляется полоса прокрутки, но она всегда находится в верхней позиции, и я не могу иметь полный live-view - person scmg; 09.07.2015
comment
@scmg. Ответ отредактирован для защиты от закрытия фигуры и прокрутки текстового поля - person Hoki; 09.07.2015
comment
Большое спасибо за ваше дополнение, я бы проголосовал 3 раза, если бы мог! И извините, что я не разделил на 2 вопроса, так как они кажутся близкими. Для части scroll_to_bottom я также нашел на undocumentedmatlab.com, однако для замораживающей части я бы использовал enableDisableFig того же автора на Matlab fileexchange, так как только с onCleanup пользователь по-прежнему может закрыть графический интерфейс до того, как все части после того, как команды DOS (команды DOS - это не все в обратном вызове моей кнопки) еще не завершены, что также приводит к ошибкам. Еще раз спасибо за все. - person scmg; 10.07.2015
comment
@scmg, для заморозки вам не нужно прибегать к внешней функции. Вы можете установить флаг перед запуском команды dos, затем в CloseRequestFcn вы просто ничего не делаете, пока флаг не сброшен (хотя не забудьте сбросить флаг после завершения команды dos). - person Hoki; 10.07.2015
comment
извините, я имел в виду не только закрытый графический интерфейс, но и взаимодействие с другими компонентами, любой другой более простой способ, чем эта внешняя функция? - person scmg; 10.07.2015
comment
Давайте продолжим обсуждение в чате. - person Hoki; 10.07.2015

Matlab не предлагает собственный способ непрерывного получения результатов во время выполнения dos, unix и system. Тем не менее, есть возможность добиться желаемого поведения.

Предлагаемый обходной путь:

  • Выполните свою команду и передайте вывод в файл.
  • Используйте символ & для продолжения выполнения кода Matlab.
  • Постоянно читайте содержимое этого файла и соответствующим образом обновляйте графический интерфейс.
  • Введите второй временный файл, указывающий конец команды, чтобы остановить процесс обновления.

Вот код:

% create figure and uicontrol
fh = figure;
txtbox = uicontrol(fh,'Style','edit','Max',30,'Min',0,...
                   'HorizontalAlignment','left',...
                   'FontName','FixedWidth',...
                   'Position',[30 30 450 200]);

% store current path
path = cd;

% delete token to make sure the loop continues as expected
warnstate = warning('off','MATLAB:DELETE:FileNotFound');
delete(fullfile(path,'temp_cmdlog_done'));
warning(warnstate); % restore original warning state

% execute dos-command in background
cmd = 'ping -c 5 192.168.200.1';
dos([cmd,' > temp_cmdlog && echo > temp_cmdlog_done &']);

% refresh text in uicontrol until dos-command is done
while 1
    out = fileread('temp_cmdlog');
    set(txtbox,'String',out);
    if exist(fullfile(path,'temp_cmdlog_done'),'file')
        break;
    end
    pause(0.2); % adjust to suit your needs
end

% delete the temporary files
delete(fullfile(path,'temp_cmdlog'));
delete(fullfile(path,'temp_cmdlog_done'));

% indicate that process finished
set(txtbox,'ForegroundColor',[0,0.5,0]);
person Matt    schedule 09.07.2015
comment
но использование & в конце будет держать cmd-Window открытым в фоновом режиме, можно ли как-то избежать этого? - person scmg; 09.07.2015
comment
Кстати, я думаю, что это должен быть один & в > temp_cmdlog && echo > temp_cmdlog_done - person scmg; 09.07.2015
comment
@scmg Чтобы протестировать приведенный выше скрипт, я использовал OSX и команду system. Именно по этой причине я использовал &&, потому что другие версии у меня не работали. Если вы подтвердите, что это работает с одним &, я изменю его. Я не знаю прямого решения, как закрыть окно. - person Matt; 09.07.2015