How to redirect stdout to a text box in a UI?
12 views (last 30 days)
Show older comments
Rachel Soreq
on 5 Oct 2016
Edited: Delprat Sebastien
on 16 Jan 2024
I'm using R2016b and would like to create a UI using the new app developer tool. I'm using the UI to wrap a rather long execution process and would like the user to be able to follow the messages the software is generating as it progress. Is it possible to redirect the standard output from the screen to a text box inside the UI and have it refresh as it goes?
Thanks,
Rachel
1 Comment
Joe Yeh
on 5 Oct 2016
By standard output, do you mean command window ? What are the functions that generate these outputs ?
Accepted Answer
Walter Roberson
on 5 Oct 2016
No.
You might be able to diary() into a file and while it is running, read the file. The prospects are uncertain on ms windows due to the way file locks are done.
The two mechanisms for grabbing a copy of MATLAB output are diary and evalc(), but evalc cannot be queried while the code is running. The diary approach would require timers unless you had the cooperation of the code.
If you have the parallel computing toolbox then another method of getting completed output is parfeval
More Answers (1)
Delprat Sebastien
on 16 Jan 2024
Edited: Delprat Sebastien
on 16 Jan 2024
Here is a Piece of Code that works using Events
clearvars
close all
clc
% Create a process
pProcess = System.Diagnostics.Process();
% Set filename and any options here
pProcess.StartInfo.FileName = "your program.exe";
pProcess.StartInfo.Arguments = "some options";
pProcess.StartInfo.WorkingDirectory = pwd;
% Other options
pProcess.StartInfo.UseShellExecute = false; % Use shell or not to start process
pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.StartInfo.RedirectStandardError = true;
pProcess.StartInfo.CreateNoWindow = true; % Set this to false if you want the process to create a windows
% Create event listener (there is a third one,"Exited" triggered when the process is ended)
% You may use any callback function in the form of myEventListener(src,event)
% Here, I simply use a disp command for simplicity
listener1 = addlistener(pProcess, 'OutputDataReceived', @(src, event) disp(['Ok' char(event.Data)]));
listener2 = addlistener(pProcess, 'ErrorDataReceived', @(src, event) disp(['err ' char(event.Data)]));
% Start the process
pProcess.Start();
% Read stdout & stderr
pProcess.BeginOutputReadLine()
pProcess.BeginErrorReadLine()
% Wait for exit
pProcess.WaitForExit();
You may change the event listener by any function of you choice:
function myEventListener(src,event)
% do something with the event here
end
This works well in a script because the process remains in the workspace once the program is ended.
If now, the whole code is enclosed within a function, the function will terminate just after the WaitForExit. But due to Matlab processing time, it is highly probable that some events remains unprocessed by the event listner (Matlab event may not have a priority high enough, or is simply too slow. I do not really know why it happens, but I experienced it). As a result, the function will terminate and all the objects (process, event listeners) will be deleted, and possibly many event can remain unprocessed (especially if the program run by the process terminates very quick).
An uggly fix consists in adding a pause after pProcess.WaitForExit()... It is uggly because there is no really whay to know how long it will takes. So, it can be better to do a poll.
So one way to deal with this is to "poll" the redirected outputs explicitely. The programs looks like this:
% Create a process
pProcess = System.Diagnostics.Process();
% Set filename and any options here
pProcess.StartInfo.FileName = "your program.exe";
pProcess.StartInfo.Arguments = "some options";
pProcess.StartInfo.WorkingDirectory = pwd;
pProcess.StartInfo.UseShellExecute = false;
pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.StartInfo.RedirectStandardError = true;
pProcess.StartInfo.CreateNoWindow = false;
Start(pProcess);
% Retrieve stdout & stderr stream
stdErrOutput='non empty';
outdErrOutput='non empty';
% Loop while process is running or there are some outputs
out='non empty';
while ~pProcess.HasExited || ~isempty(outdErrOutput) || ~isempty(stdErrOutput)
% Read stderr
stdErrOutput = string(stderr.ReadLine);
if ~isempty(stdErrOutput)
% Do something with the line
disp(stdErrOutput);
% Sometimes adding a small pause leaves enough time to Matlab to
% refresh. Within an APP, use redraw
pause(0.01);
end
% Read strdout
outdErrOutput = string(stdout.ReadLine);
if ~isempty(outdErrOutput)
disp(outdErrOutput);
% Sometimes adding a small pause leaves enough time to Matlab to
% refresh. Within an APP, use redraw
pause(0.01);
end
end
With this two code, you should be able to find a solution to your problem.
1 Comment
Rik
on 16 Jan 2024
While it does look like useful code, I don't see how this answers the original question. Can you explain that?
See Also
Categories
Find more on Adding custom doc in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!