matlab - 将 dos 命令输出显示为静态文本

matlab - display dos command output to static text

我正在使用 GUI 调用终端命令。通过使用 dos(my_command, '-echo') 我可以在 Matlab 的命令 Window 中获得命令输出。有没有办法在我的 GUI 的静态文本中复制 -echo

目前,使用 my_command,我将输出写入 log 文件,并在处理完成后通过此 log 文件更新静态文本的字符串,但我想要的是a live-view like in Command Window: 输出实时逐行显示。谢谢。

更新:

@Hoki:另一个问题是:当控制台命令正在执行时,如果我关闭 GUI 然后 Matlab returns 错误无法阻止,我如何冻结整个 GUI 直到命令完成?

Matlab 不提供在 dosunixsystem 执行期间连续获取结果的本机方法。尽管如此,仍有可能实现所需的行为。

这是建议的解决方法:

  • 执行您的命令并将输出通过管道传输到文件。
  • 使用 & 字符继续执行 Matlab 代码。
  • 持续读取此文件的内容并相应地更新 GUI。
  • 引入第二个临时文件,指示停止更新进程的命令结束。

代码如下:

% 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]);

感谢 Yair Altman 在这个 article 中提供的信息,我得到了一些工作,但它涉及侵入 Matlab Java 基础对象(即命令 window)。

它涉及将侦听器附加到 Matlab 命令 window。现在要小心,经常保存你的工作,并准备好多次终止 Matlab 进程,直到你做对......因为每次你在代码中出现错误时,你都会陷入一种无限循环(error/warning 被发送到命令 window,它会触发您的侦听器,它会重新触发错误等...)。为了让下面的示例以稳定的方式工作,我不得不重新启动 Matlab 很多次。

这也是我暂时只附加监听器的原因。就在发送 dos 命令之前,我在之后直接删除了监听器。您可以永久保留监听器或根据您的需要进行调整,但请记住上面的建议。还要考虑到命令 window 可以包含大量字符,您可能不希望在文本框中全部包含这些字符,因此您必须管理从中获得的文本(如示例中所示,取一个子集),并考虑是否要 append 或只是 refresh 文本框中的文本。

下面的例子似乎是稳定的,任何修改风险自负;-)

在评论中请求后,我添加了 3 个函数:

  • 一个onCleanup。这是一个 Matlab 功能,允许在出现问题时采取最后的手段(一种 "catch all" 机制)。强烈建议使用 未记录的 函数用于此类程序。

  • A myCloseRequestFcn 拦截 window 的关闭动作以移除侦听器并避免错误循环。

  • 一个scroll_to_bottom函数。这允许将文本框插入符号移动到文本的末尾(= 滚动到底部以防文本多于可见 space)。

警告: 最后一个功能可能需要一个单独的问题,并再次调用 未记录的 功能(因此永远无法保证兼容性)。为了能够实现它,您需要 在您的 Matlab 路径中使用 findjobj 函数。如果您不想下载外部组件,那么 delete/comment 使用它的代码部分和子函数 scroll_to_bottom (忘记滚动文本框,在纯 Matlab 中无法做到这一点). 或者您可以通过查看 post.

的编辑历史来选择以前版本的代码
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',[]) ;