How to interrupt file operations with a GUI callback function?
3 Ansichten (letzte 30 Tage)
Ältere Kommentare anzeigen
WorkerBee
am 18 Dez. 2021
Kommentiert: WorkerBee
am 20 Dez. 2021
Hi –
I’m running MATLAB 2019b and Windows 10.
I’m building a GUI in the App Designer, and I have a “Start” button a “Cancel” button and a TextArea control, among other things, in the GUI. When the user clicks the start button, it invokes a method of a custom class that starts importing a list of .csv files with the MATLAB readtable function. The individual files being imported are rather large (occasionally upwards of 500mb), so readtable takes somewhere between 10-30 seconds to import each file.
I’ve set the app up to give the user an update each time a file finishes importing (e.g. “File 1 of 10 imported”). These updates are displayed in the TextArea control on the GUI.
If the user clicks the cancel button while the data importation function is going, it sets a flag in a persistent variable within the custom class. The data import function checks the persistent variable each time before it starts to import a new file, and if it sees that the user has clicked cancel it will drop out of the loop. This works perfectly, but the data import function can only check the cancel flag once every 10-30 seconds because it’s waiting for readtable to finish.
I would like to give the user some indication that the cancel button has performed its function so I can avoid things like impatient users ending tasks via the task manager. Ideally, as soon as the user clicks cancel, a message would be printed to the TextArea that says “Cancelling operation…”, then readtable can finish what its working on at its leisure. However, I can’t seem to get the cancel button callback function to interrupt the readtable function, although it will interrupt the data import function as soon as readtable finishes. That means I have a 10-30 second delay between when the user clicks cancel and when they see some response from the GUI.
Both the start and cancel buttons are configured as interruptible in the app designer properties, if that has any relevance.
Anyone out there have a good idea of how to solve this problem?
Here’s some (vastly simplified) example code:
%% public functions from GUI app %%
function PrintMessage(app, Message)
% prints the provided message to a TextArea control in the GUI
app.MessageLogTextArea.Value = [Message newline app.MessageLogTextArea.Value];
drawnow
end
%% Private functions from GUI app %%
function StartButtonPushed(app, event)
% start button callback function
% reset the cancel flag to false
MyDataClass.SetGetCancelFlag(false);
% start the data import function
ImportData(app.MyDataClassObject, @(Message)PrintMessage(app,Message));
end
function CancelButtonPushed(app, event)
% cancel button callback function
% inform user that the cancellation process has started
PrintMessage(app, 'Cancelling operation...');
% set the cancel flag to true
MyDataClass.SetGetCancelFlag(true);
end
%% MyDataClass definition %%
classdef MyDataClass < handle
properties
ImportFileList (:,1) cell
ImportedData (:,1) cell
end
methods
function MyDataClassObject = MyDataClass
% constructor method
MyDataClassObject.ImportedData = cell.empty(0,1);
end
function ReturnValue = SetGetCancelFlag(NewFlagValue)
% sets or returns the value of the cancel flag
persistent CancelFlag
if nargin
CancelFlag = NewFlagValue;
end
if isempty(CancelFlag)
CancelFlag = false;
end
ReturnValue = CancelFlag;
end
function ImportData(MyDataClassObject, PrintFunction)
% imports data from .csv files using readtable
NumberOfFiles = size(MyDataClassObject.ImportFileList,1);
for Counter = 1:NumberOfFiles
% check if user cancelled the operation
if MyDataClass.SetGetCancelFlag()
PrintFunction('Operation cancelled by user.');
return
end
% import the next file
ImportedTable = readtable(MyDataClassObject.ImportedFileList{Counter});
MyDataClassObject.ImportedData = [MyDataClassObject.ImportedData; {ImportedTable}];
% update the user
PrintFunction(['File ' num2str(Counter) ' of ' num2str(NumberOfFiles) ' imported.']);
end
end
end
end
0 Kommentare
Akzeptierte Antwort
Voss
am 18 Dez. 2021
If for whatever reason you cannot follow either of @Walter Roberson's suggestions in his answer, it might be worthwhile to consider replacing the call to readtable with some code of your own which can periodically query the state of CancelFlag and abort if necessary. It will likely be slower than readtable (probably much slower, but not necessarily, because the code only needs to support the specific format(s) of csv files your program needs to support), but it would allow the opportunity to respond more quickly to the Cancel button press. It will be a tradeoff between the speed of loading the files and the responsiveness of cancelling at will.
Again, a separate thread or parallel processing is best, but if those are not feasible, then writing your own code to do what readtable does may be worth thinking about, because otherwise I don't know how you would do it.
2 Kommentare
Walter Roberson
am 19 Dez. 2021
For example you could potentially use textscan() with a specific format, and specify a repetition count after the format, so it only processes that many times in one call.
Weitere Antworten (1)
Walter Roberson
am 18 Dez. 2021
Bearbeitet: Walter Roberson
am 18 Dez. 2021
R2021b or later, you could put the reading operation into a background thread. Which you could potentially even cancel()
In your r2019b release, Parallel Computing toolbox would permit the same thing.
0 Kommentare
Siehe auch
Kategorien
Mehr zu Variables finden Sie in Help Center und File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!