MATLAB fails to execute line with uigetfile-- why?

I call a function using uigetfile() from another function, but when it runs, MATLAB seems to ignore the line entirely. (The function runs just fine when called from the command line.)
The function is simply:
function [sl] = InputSeaLevel()
%InputSeaLevel prompts for the location of a file containing sea level data
[fname,pname]=uigetfile('*.mat','Select the file containing sea level data');
varname=load(strcat(pname,fname));
name=fieldnames(varname); sl=getfield(varname,name{1});
end
The script that calls InputSeaLevel() does so from within an if loop-- specifically, an if loop created to parse the output from a menu box, e.g.:
c=menu('Make a choice','Yes','No');
if c==1
sl=InputSeaLevel();
{more code}
else
{other code}
end
I successfully ran the function from the command line from within the following loop:
a=1;
if a==1
sl=InputSeaLevel();
end
and the function runs well when removed from the if loop, so I believe that the if loop itself (or perhaps the use of menu() is the problem. I do use eval in an earlier script:
eval([XYZ_var '= tempXYZ;';])
eval([StackName '= stackXYZ;';])
but I don't believe these lines are the cause of the problem, since the problem still occurs when these lines are commented out.
I've seen some discussion of similar problems with uigetfile() before (see here), but I haven't understood the proposed solutions-- presumably the dialog box opened by menu() (and closed when one of its option buttons is clicked) shouldn't be stuck waiting for a response. I don't follow the explanation for how to force any open (but somehow hidden) dialogs to stop waiting, and I don't understand how it could still be open to begin with.
I am running MATLAB R2013a from a Windows 7 machine.
Does anyone have an explanation for what is about this code that is preventing MATLAB from "seeing" uigetfile() when it executes my function? Does anyone know what I can do to either avoid or circumvent this (without simply excluding the function or removing it from the if statement)?
Thanks in advance!

3 个评论

Sarah - when you run the script, with all code as you described above, does the menu appear to the user to select the yes/no choice? Where are you running your script from - the Command Window or from a GUI?
I'm able to run the above snippet of code that correctly displays the menu and correctly opens the file chooser. Could you attach your script to your question so that we can take a look at it, and maybe reproduce the error?
The solution (at least as posted by the OP) to the problem there was to make sure his previous function had an end statement (to ensure cleanup code was executed in sequence apparently). This sounds flaky to me but for that to have any pertinence to your problem you'd need a structure similar to that described there.
That would mean the function containing the call to your function needs an end attached to it. But, you say "script", not function. It still seems unlikely that the diagnosis was really the cure there but to see if it has legs turn your script into a function (not necessary to have arguments or return, just function) and then try it with/without the end statement explicitly included.
Geoff and dpb-- thanks for your responses. I have attached the code that's generating the error for me-- it's sort of an all-in-one script for automated data processing, so it calls several other scripts (ReadXYZ) and functions (InputSeaLevel, GridXYZ), also attached.
I ran the example code from the initial post in my command window and hit the same error-- a screen capture of the example code as run is attached so that you can see the exact error, which occurs not in the line containing uigetfile, but in the next line, which uses the output of uigetfile.)
The menu box does appear in the code when it is called, and it seems to work normally (i.e., it disappears when the Yes or No button is clicked and returns the proper value according to the button).
The problem does not happen when I run InputSeaLevel() itself (the function that calls uigetfile) from the command line, but it does happen when I call InputSeaLevel from the all-in-one script--specifically, from within the if loop after the menu() command. (It runs fine when called before menu()-- which very much implicates menu() as the cause of all this, even if it's not clear how or why.)
I have tried running the guts of InputSeaLevel() without the function wrapper (i.e., simply the text of lines 3 through 5) directly in ProcessXYZ, but it still generated the error. I've also tried converting ProcessXYZ to a no-input, no-output function with the same results.
The problem happens regardless of whether I'm running ProcessXYZ from the command window or through the GUI on the code editor, and really does seem to be that MATLAB simply ignores the line that calls uigetfile().
Thanks again for your help!

请先登录,再进行评论。

回答(2 个)

Maria - I get that same error message
Warning: Input should be a string.
> In strcat at 83
In InputSeaLevel at 4
Warning: Input should be a string.
> In strcat at 91
In InputSeaLevel at 4
Error using load
File name is empty.
Error in InputSeaLevel (line 4)
varname=load(strcat(pname,fname));
if I run the code and choose not to select a file i.e. press the Cancel button. Is this what you are doing, or are you in fact selecting a file?
The InputSeaLevel code should be modified to handle the case of the user not selecting a file
function [sl] = InputSeaLevel()
[fname,pname]=uigetfile('*.mat','Select the file containing sea level data');
% if no file selected, then fname is a double - so check for char/string
if ischar(fname)
varname=load(strcat(pname,fname));
name=fieldnames(varname);
sl=getfield(varname,name{1});
else
% raise error indicating no file selected
error('InputSeaLevel - no file selected!');
end
-------------
As for running your script, if I create one or more dummy text files with 26 numeric elements in it (as per the specification) and run ProccessXYZ, I am prompted for a directory (for the XYZ data), I then see the menu (from which I select yes), and then I'm prompted with the file chooser, and the code runs to completion if I have chosen a file.
Have you thought about stepping through the code in the debugger? i.e. put a breakpoint in ProcessXYZ at line 10
if c1==1
and then re-run ProcessXYZ. What is the value of c1, at this point, when the user has selected Yes in the menu.

4 个评论

Thanks for your response! The issue seems to be that MATLAB simply does not execute the line containing uigetfile(), as though it is commented out. That is, the file chooser window never appears and MATLAB continues running the code as though I have entered cancel, even though the window never popped up.
I know that it isn't a problem with the function that calls the file chooser gui, because when I run the function by itself (either through the command window or in the editor), it runs as designed. Moreover, this problem (where MATLAB fails to open the file chooser/fails to "see" or execute the line containing that command) only seems to happen when the call to uigetfile() is contained within an if statement. The if statement is constructed correctly for the output of menu(), since MATLAB attempts to call the function InputSeaLevel().
I have stepped through the code with a debugger. In de-bug mode, the code runs well as I step through it. The error happens outside debug mode. (It's almost as if the debugger forces MATLAB to execute every line in a way that simply running the code does not.)
Sarah - I don't understand why I can run the code and it works, yet you can't! Weird.. :)
Can you try the following - replace (in the ProcessXYZ.m file)
if c1==1
with
if 1==1
That way, the if condition should always evaluate. Should be no different than commenting out (which I know you have tried), but just out of curiosity...
Also, have you tried commenting out the line
ReadXYZ
from ProcessXYZ.m? What happens if the code ignores this script? When you try this example, please put back the
if c1==1
EDIT
Also, in ReadXYZ, the final statement is to clear a number of variables. Perhaps replace the clear with
clearvars XYZ* ans r c dataArray delimiter formatSpec olddirectory ...
startRow tempXYZ StackName col*
just in case something other than a variable is being cleared (though I have no idea what that could be - am just grasping at straws!). This will ensure that only variables that match the input var names are cleared.
Thanks again, Geoff. I tried changing the conditional statement to 1==1, and that didn't help-- MATLAB was already entering the if loop to try to run InputSeaLevel. I edited the last statement in ReadXYZ to use the clearvars command, too, without effect. (If nothing else, that's probably a best practice I should generally adopt. Thanks for making me aware of it.)
I tried commenting out the ReadXYZ, and, voila, the code worked. Once. (I tried it a second time to be sure and for reasons unknown, it failed.) I can't makes heads or tails of why it worked-- and why it subsequently failed to work.
I think I may chalk this up to a computer (or institution)-specific issue, since you and the other commenters haven't been able to reproduce the bug using my codes (or even my simplified if statement), but my officemate could.
Thank you again for all your help-- one day I will figure this out and post a more definitive answer. Until then, people are just going to have to load sea level manually. (Or find the answer themselves!)
Good luck, Sarah! One thing you may want to consider doing is following the suggestion from dpb and make your ReadXYZ and ProcessXYZ into functions (with the end as the last line for each). Just to see what happens.
One other positive benefit of making functions is that all variables are local to the function and so don't populate the base workspace. This removes the need for the clearvars or other statements. I realize that some of your variables from ReadXYZ need to be made available to ProcessXYZ, and they could be with just simple return to the function signature. For example, the first line of ReadXYZ becomes
function [stackXYZ,RunName,SaveDir] = ReadXYZ
and you can remove the clearvars at the end.
And the first couple of lines of ProcessXYZ becomes
function ProcessXYZ
close all
%%Loading and Gridding
%Loads the data and combines them into a single "stack" of output arrays
[stackXYZ,RunName,SaveDir] = ReadXYZ;
__
And the final thing I will say about the uigetfile problem and how when you commented out ReadXYZ it worked the first time but not the second. Could this have to do with some of the script variables (now in the base workspace) conflicting with some built-in function name? Anyway, if you have time, then please try the above.

请先登录,再进行评论。

It looks like you are running into the bug which is described here:
https://www.mathworks.com/support/bugreports/895795
The menu function creates a figure which after you have made a choice is deleted. This then leads to a threading issue which can be resolved by calling drawnow between calling menu and uigetfile.

类别

帮助中心File Exchange 中查找有关 App Building 的更多信息

产品

提问:

2014-7-31

回答:

2015-1-23

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by