Search code examples
matlabbatch-filecmdlogfile

matlab - display dos command output to static text


i am using GUI to call a terminal command. By using dos(my_command, '-echo') i can get the command output in Matlab's Command Window. Is there anyway to replicate that -echo in a static text in my GUI?

Currently, with my_command, I write the output to a log file, and update the static text's String by this log file after process finishes, but what I want is a live-view like in Command Window: output is displayed line by line in real-time. Thanks.

Update:

@Hoki: another question is: when the console commands are being executed, if I close the GUI then Matlab returns errors unstopable, how can I freeze the whole GUI until the commands are finished?

enter image description here


Solution

  • Thanks to Yair Altman info in this article, I got something to work but it involves hacking into Matlab Java base objects (namely the command window).

    commandWindowGui

    It involves attaching a listener to the Matlab command window. Now be careful, save your work often and be prepared to kill Matlab process quite a few times until you get it right ... because every time you have an error in the code you are stuck in a kind of infinite loop (the error/warning is sent to the command window, which triggers your listener, which re-trigger the error etc ...). I had to restart Matlab a good dozen of times just to get the example below to work in a stable way.

    That's also the reason why I only attach the listener temporarily. just before sending the dos command and I remove the listener directly after. You can leave the listener permanently or adjust that to your needs but remember the advice from just above. Also consider that the command window can hold a massive amount of character, which you may not want all in your textbox, so you have to manage the text that you get from it (take a subset as in the example), and consider if you want to append or simply refresh the text in the textbox.

    The example below seems to be stable as it is, any modification at your own risks ;-)

    After request in comment I added 3 functions:

    • An onCleanup. This is a Matlab functionality to allow last resort action in case something goes wrong (a kind of "catch all" mechanism). Heavily recommended for this kind of program using undocumented functions.

    • A myCloseRequestFcn which intercept the closing action of the window to remove the listener and avoid error loops.

    • A scroll_to_bottom function. This one allows to move the text box caret to the end of the text (= to scroll to the bottom in case there is more text than visible space).

    Warning: The last functionality could deserve a separate question and again call for undocumented functionality (so the compatibility is never guaranteed). To be able to implement it you need to have the findjobj function available in your Matlab path. If you do not want to download external component, then delete/comment the part of code that uses it and the subfunction scroll_to_bottom (and forget about scrolling the text box, there is no way to do that in pure Matlab). Or you can pick the previous version of the code by looking at the edit history of the 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',[]) ;