【问题标题】:matlab - display dos command output to static textmatlab - 将dos命令输出显示为静态文本
【发布时间】:2015-07-09 01:56:17
【问题描述】:

我正在使用 GUI 调用终端命令。通过使用dos(my_command, '-echo'),我可以在 Matlab 的命令行窗口中获得命令输出。无论如何要在我的 GUI 中以静态文本复制 -echo 吗?

目前,使用my_command,我将输出写入log 文件,并在进程完成后通过此log 文件更新静态文本的字符串,但我想要的是live-view,就像在命令行窗口中一样:输出实时逐行显示。谢谢。

更新:

@Hoki:另一个问题是:在执行控制台命令时,如果我关闭 GUI,Matlab 会返回无法停止的错误,如何冻结整个 GUI,直到命令完成?

【问题讨论】:

标签: matlab batch-file cmd logfile


【解决方案1】:

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

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

这也是我暂时只附上监听器的原因。就在发送dos 命令之前,我直接删除了监听器。您可以永久离开听众或根据您的需要进行调整,但请记住上面的建议。还要考虑命令窗口可以包含大量字符,您可能不希望所有字符都在文本框中,因此您必须管理从中获取的文本(如示例中的子集),并考虑您是否想要追加或只是刷新文本框中的文本。

下面的例子看起来很稳定,任何修改都需要您自担风险;-)

在评论请求后,我添加了 3 个功能:

  • onCleanup。这是一个 Matlab 功能,允许在出现问题时采取最后的措施(一种“包罗万象”的机制)。强烈推荐使用 undocumented 函数的此类程序。

  • 一个myCloseRequestFcn 拦截窗口的关闭动作以移除监听器并避免错误循环。

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

警告:最后一个功能可能值得单独提问并再次调用未记录功能(因此永远无法保证兼容性)。为了能够实现它,您需要在您的 Matlab 路径中提供 findjobj 函数。如果您不想下载外部组件,请删除/注释使用它的代码部分和子函数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',[]) ;

【讨论】:

  • 我会先尝试将它混合到我的 GUI 中然后再回来
  • 我试过了,但还是有一个问题:如果日志太长,如何将文本位置设置在末尾?
  • @scmg。我不明白你的问题。你的意思是在命令窗口的末尾设置副本的开始位置?
  • 不,我的意思是:如果 DOS 中的输出太长,那么文本框总是显示日志的第一部分,我怎样才能让它显示日志的最后部分,比如我更新的图片有问题?
【解决方案2】:

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

【讨论】:

  • 但最后使用& 会使cmd-Window 在后台保持打开状态,有什么办法可以避免吗?
  • 顺便说一句,我认为它应该是> temp_cmdlog && echo > temp_cmdlog_done中的单个&
  • @scmg 为了测试上面的脚本,我使用了 OSX 和 system-command。这就是我使用&& 的原因,因为其他版本不适合我。如果您确认它适用于单个 &,我会更改它。我不知道如何关闭窗口的直接解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
  • 2011-03-07
  • 1970-01-01
相关资源
最近更新 更多