Integrating multiple callbacks in a GUI window
Mostrar comentarios más antiguos
I have been trying for an extended period of time to share data among the apps of a GUI window. I have several codes to format data and navigate through but each time i attempt to create a common code between callbacks I generate an error. I have looked at the MathWorks page for sharing data among callbacks with no luck as of yet. At the moment I need to create a window with an axis, a push button and a slider so that i can test if my slider code is working.
function varargout = push_slider(varargin)
% PUSH_SLIDER MATLAB code for push_slider.fig
% PUSH_SLIDER, by itself, creates a new PUSH_SLIDER or raises the existing
% singleton*.
%
% H = PUSH_SLIDER returns the handle to a new PUSH_SLIDER or the handle to
% the existing singleton*.
%
% PUSH_SLIDER('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in PUSH_SLIDER.M with the given input arguments.
%
% PUSH_SLIDER('Property','Value',...) creates a new PUSH_SLIDER or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before push_slider_OpeningFcn gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to push_slider_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help push_slider
% Last Modified by GUIDE v2.5 06-Apr-2017 13:10:23
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @push_slider_OpeningFcn, ...
'gui_OutputFcn', @push_slider_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before push_slider is made visible.
function push_slider_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to push_slider (see VARARGIN)
% Choose default command line output for push_slider
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% UIWAIT makes push_slider wait for user response (see UIRESUME)
% uiwait(handles.figure1);
% --- Outputs from this function are returned to the command line.
function varargout = push_slider_OutputFcn(hObject, eventdata, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
guidata(hObject, handles);
myFolder = uigetdir('C:\Users\c13459232\Documents\MATLAB'); % Generate command window to choose a folder
if ~isdir(myFolder) % if the directory is not a valid path
errorMessage = sprintf('Error: the following folder does not exist: \n%s', myFolder); % print this error message
uiwait(warndlg(errorMessage)); % block the execution of program and wait to resume
return;
end
outFolder = fullfile(myFolder, 'output'); % build full file name from parts in folder 'Output'
mkdir(outFolder); % create folder
filePattern = fullfile(myFolder, '*.asc'); % Call all files with '.asc' from the chosen folder
Files = dir(filePattern); % list folder contents
finishCell = cell(length(Files));
for k = 1 : length(Files) % for all files files in the folder
baseFileName = Files(k).name;
FileName = fullfile(myFolder, baseFileName);
fid = fopen(FileName); % open the file from chosen folder
Cell = textscan( fid, '%d', 'delimiter', ';'); % scanning data from files
fclose(fid); % close file from chosen folder
Data = cell2mat(Cell); % convert the cell data to matrix
N = 1024; % Number of numbers per row
skip = 2;
Finish0 = reshape(Data, N, [])'; % reshape the data into the correct format
Finish1 = Finish0(1:skip:end, 1:skip:end);
finishCell{k} = Finish1;
end
% --- Executes on slider movement.
function slider1_Callback(hObject, eventdata, handles)
% hObject handle to slider1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: get(hObject,'Value') returns position of slider
% get(hObject,'Min') and get(hObject,'Max') to determine range of slider
SliderValue = get( handles.slider, 'value');
x = SliderValue;
z = (SliderValue - 1);
Value = contourf(finishCell{x,1});
PreviousValue = contourf(finishCell{z,1});
% --- Executes during object creation, after setting all properties.
function slider1_CreateFcn(hObject, eventdata, handles)
% hObject handle to slider1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor',[.9 .9 .9]);
end
I'm not sure how I can specify that the finishCell value created by the push button is what will be navigated through using the slider. Honestly any tips that anyone can provide would be greatly appreciated as staring at this code and mathworks pages has led me here as a last resort.
3 comentarios
Jan
el 10 de Abr. de 2017
I do not get the point. What is the relevant part of the code? "specify that the finishCell value created by the push button is what will be navigated through using the slider" does not let me understand exactly, what you want to achieve.
You can't have looked at the Mathworks page on sharing data among callbacks for very long if you opted to not even try any of the options it gives to share 'finishCell' between your pushbutton callback and the slider callback!
gives numerous options, none of which you have tried in the code you post. Personally I generally use the guidata option, but they all work, in certain situations.
Aaron Smith
el 10 de Abr. de 2017
Respuestas (1)
Jan
el 10 de Abr. de 2017
The guidata method is straight forward:
function OpeningFcn(hFigure, EventData, handles)
handles.Data = []; % Initialize properly
handles.Value = [];
guidata(hObject, handles); % Store ucrrent value in the figure
function CallbackXYZ(hObject, EventData, handlesFromInputs)
handles = guidata(hObject); % Get current value from figure
...
handles.Data = rand; % any modifications
disp(handles.Value); % any access
guidata(hObject, handles); % Store handles struct in the figure again
Now the handles struct is available and uptodate in each callback.
13 comentarios
Aaron Smith
el 10 de Abr. de 2017
Editada: Aaron Smith
el 10 de Abr. de 2017
Adam
el 10 de Abr. de 2017
guidata(hObject, handles);
is always used and should never change.
It just writes the updated handles struct back into the GUI after you have added something new to it.
You don't have to add things in the OpeningFcn, the same idea works across any GUIDE-defined callbacks. Callbacks you create yourself can still use this, but need a little more work to ensure you get handles in and updated correctly.
Jan
el 10 de Abr. de 2017
"hObject" is used as name of the first input of callbacks frequently. It means the handle of the object, which has triggered the callback. A "handle" is the address of a GUI element. The names "handles" for the user-defined data stored in GUIs is a really bad bad bad choice and causes confusions too often. "guidata" might be more useful, but unfortunately this is the name of the function already. :-( But it is a name only.
In my code snippet the fields "handles.Data" and "handles.Value" have been defined as example only. The got a default value in the OpeningFcn to avoid an error, if you press on the buttons in the wrong order. In your case I assume something like this is wanted:
handles.finishCell = {} % Default in the OpeningFcn
handles.finishCell = finishCell; % The definition in the callback
Aaron Smith
el 20 de Abr. de 2017
Jan
el 24 de Abr. de 2017
@Aaron: All I could do is using the debugger:
dbstop if error
Then I would run your code and click on all GUI elements in different orders. Matlab would stop if an error occurres. Then I would fix the surrounding code.
But you can do this by your own. This has the advantage that you are the one who knows exactly, what the code should do. If the code runs successfully, you can assume that it is written correctly.
Aaron Smith
el 27 de Abr. de 2017
Aaron Smith
el 28 de Abr. de 2017
Editada: Aaron Smith
el 28 de Abr. de 2017
Unless your code inside your callback either branches off, passing handles into some other function (in which case, if that function edits anything other than a graphical object or handle-derived class object it will need to return handles as an output argument and reassign it) or triggers some listener (unlikely in your case) that causes the code to jump somewhere else where handles is being used then you just need a single
guidata( hObject, handles )
at the end of the callback. e.g in your case the 'pushbutton' that you add will just get lost instantly when the callback ends because you added it after the guidata.
guidata simply replaces the 'handles' stored in the GUI with the one you give it from your callback. It only needs to be done when your local version of handles is about to go out of scope, or in the cases I mentioned above which don't seem to be relevant to your code.
So long as guidata is called at the end of a callback all your changes to handles will be stored and available in whichever callback is next triggered.
Aaron Smith
el 2 de Mayo de 2017
Adam
el 2 de Mayo de 2017
I'm not sure I get what you are asking. Data gets thrown away each time round the loop, but you are storing it in your
finishCell
cell array.
If you want to access this in another callback then just something like
handles.finishCell = finishCell;
after the for loop and before the guidata call would make this available elsewhere.
Aaron Smith
el 3 de Mayo de 2017
Adam
el 3 de Mayo de 2017
You shouldn't need any subfunctions to share data, just attach it to the handles structure.
I would strongly advise more meaningful variable/field names though as yours are extremely confusing.
You have a field on your handles structure called 'pushbutton' which looks like it is a cell array from the way you access it. Then you have another called 'slidervalue' which looks like it is a graphics object handle to a contour plot.
In the case of 'Data', it is up to you whether you store it or not. You could just access it directly in your pushbutton4 (again, give it a more meaningful tag!) callback as
Data = handles.pushbutton{ get( handles.slider1, 'value' ), 1 };
I used slider1 here as that seems to make sense although in your code you use handles.slider in slider1_Callback. I don't know if this is just a typo, but it is odd otherwise to access the value of a totally different slider in your slider callback!
Aaron Smith
el 3 de Mayo de 2017
Categorías
Más información sobre Environment and Settings en Centro de ayuda y File Exchange.
Productos
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!