The code below works. You can copy-paste this code in case you don't understand what I ask below.
In my gui, I have a pushbutton, popupmenu and edittext. Pushbutton enables adding new strings to popupmenu with the answers obtained from inputdlg. The strings in popupmenu have additional information which is defined in windowType function. When scrolling between popupmenu list, pmh_call calls windowType function and displays the information on edittext. The information on windowType function is predefined. However, what I want is to add new window types and information to this function. This is the first time I develop a GUI. So, I may have started this saving new info business to a function all wrong. Any help is appreciated.
function [] = mygui(varargin)
S.fh = figure('Visible','on','numbertitle','off','Name','Gunebakan GUI',...
'units','pixels','Position',[500 500 200 100]);
S.pbh_definewindow = uicontrol(S.fh,'Style','pushbutton','String','Define window',...
'HorizontalAlignment','center','BackgroundColor',[0.6602 0.0234 0.2539],...
'Position',[10 80 100 20]);
S.pmh_window = uicontrol(S.fh,'Style','popupmenu','String',{'Type1','Type2'},...
'Value',1,'BackgroundColor','w','Position',[10 50 150 18]);
S.eth_windowlength = uicontrol(S.fh,'Style','edit','String','4','Position',[10 10 50 20]);
set(S.pbh_definewindow,'callback',{#pbh_call,S});
set(S.pmh_window,'callback',{#pmh_call,S});
function [] = pmh_call(varargin)
S = varargin{3};
string = get(S.pmh_window,{'String','Value'});
string = string{1}(string{2});
[ windowtypeinfo ] = windowType( string );
str = num2str(windowtypeinfo.length);
set(S.eth_windowlength,'String',str);
function [] = pbh_call(varargin)
S = varargin{3};
error = 1;
prompt = {'Type name:','Type length:'};
name = 'Yeni Agac Tanimlama';
numlines = 1;
defaultanswer = {'benimagacim','2'};
answer = inputdlg(prompt,name,numlines,defaultanswer);
options.Resize = 'on';
options.WindowStyle = 'normal';
options.Interpreter = 'tex';
q = get(S.pmh_window,'String');
error = 1;
while error == 1
if ~any(strcmpi(answer{1},q))
error = 0;
else
answer(1) = inputdlg('Type name already used, enter another!')
error = 1;
end
end
P = get(S.pmh_window,{'string','value'});
q(length(q)+1) = answer(1);
set(S.pmh_window,'string',q);
function [ windowtypeinfo ] = windowType( string )
if strcmpi(string,'Type1')
windowtypeinfo.typename = 'Type1';
windowtypeinfo.length = 4;
elseif strcmpi(string,'Type2')
windowtypeinfo.typename = 'Type2';
windowtypeinfo.length = 5;
end
The question isn't really well posed but I think I understand what you're asking. To answer your final thought, I would say there is a better way to store your data. Consider the following simplified example:
function testgui
% Initialize GUI
h.myfig = figure;
h.mybutton = uicontrol( ...
'Style', 'pushbutton', ...
'Units', 'normalized', ...
'Position', [0.15 0.70, 0.70 0.15], ...
'String', 'Add Style' ...
);
h.mymenu = uicontrol( ...
'Style', 'popupmenu', ...
'Units', 'normalized', ...
'Position', [0.15 0.50 0.70 0.10], ...
'String', ' ' ...
);
h.myedit = uicontrol( ...
'Style', 'edit', ...
'Units', 'normalized', ...
'Position', [0.15 0.15 0.70 0.10], ...
'String', ' ' ...
);
set(h.mybutton, 'callback',{#addwindow, h});
set(h.mymenu, 'callback',{#changewindow, h});
% Initialize data structure
mydata(1).typename = 'Type1';
mydata(1).windowlength = 4;
mydata(2).typename = 'Type2';
mydata(2).windowlength = 5;
updatepopup(mydata, h);
% Set initial editbox value
set(h.myedit, 'String', mydata(1).windowlength);
% Store data for later
guidata(h.myfig, mydata);
end
function updatepopup(mydata, h) % Update strings in popup menu based on data array
typenames = {mydata.typename}; % Collect all the existing typenames
set(h.mymenu, 'String', typenames); % Update popup menu
end
function addwindow(~, ~, h) % Prompt user to add window
prompt = {'Type name:','Type length:'};
name = 'myprompt';
nlines = 1;
defaultanswer = {'asdf', '1'};
myanswer = inputdlg(prompt, name, nlines, defaultanswer);
% Prepare new information for storage
newwindow.typename = myanswer{1};
newwindow.windowlength = str2double(myanswer{2});
mydata = guidata(h.myfig); % Pull in existing data
mydata = [mydata newwindow]; % Add new data to existing data
updatepopup(mydata, h); % Update popup menu
guidata(h.myfig, mydata); % Store data for later
end
function changewindow(~, ~, h) % Update editbox based on popup menu selection
mydata = guidata(h.myfig); % Pull in stored data
windowselected = get(h.mymenu, 'Value'); % Get index of window selected
set(h.myedit, 'String', mydata(windowselected).windowlength); % Change editbox
end
Rather than manually getting your window type with a separate function (windowType() in your example), I would try storing your data in the GUI as a data structure and pulling it out as necessary. This allows you to use more generalized code and not have to think about how to handle every case with the loop you have now. Hopefully this is easy to follow and adapt to your needs.
You should use guide in order to easily develop GUI's in MATLAB. If you do, you will find that each element in your GUI is called by a handles.something.
For example:
Lets say that you want to add the string in the inputdlg to your popup menu, you should do something like this:
set(handles.popupMenu,'String',[predefStrings; get(handles.inputdlg,'String')]);
The 'String' argument in a popup menu must be an array of strings.
Related
I have been trying to plot two images side by side with two sliders using uicontrol. I am relatively new to uicontrol using matlab. Only the second subplot updates when I change the slider.
close all;
clear all;
clc;
set(0,'defaultAxesFontSize',14)
set(0,'DefaultFigureWindowStyle','docked')
data = rand(3,1024,64,20);
nslice = size(data,4);
nidx = size(data,1);
if nslice == 1
sampling = 1; % in some of my data nslice would be 1 so I would like my slider to not give me error in such a case
else
sampling = 5;
end
idx = 1;
slice = 1;
h.f = figure(1);
x_axis = linspace(0,0.5,size(data,3));
y_axis = linspace(0,70,size(data,2));
set(h.f,'doublebuffer','on')
h.data = data;
inst_data = squeeze(data(nidx,:,:,slice));
h.ax(1) = subplot(1,2,1,'Parent',h.f,'Units','Normalized');
imagesc(h.ax(1),x_axis,y_axis, inst_data)
colorbar;
colormap(h.ax(1),'gray')
caxis(h.ax(1),[min(abs(inst_data(:))),max(abs(inst_data(:)))])
xlabel('xaxis')
ylabel('yaxis')
title('figure 1')
h.ax(2) = subplot(1,2,2,'Parent',h.f,'Units','Normalized');
log_data = log(inst_data);
imagesc(h.ax(2),x_axis,y_axis, log_data)
colorbar;
colormap(h.ax(2),'jet')
caxis(h.ax(2),[-max(abs(log_data(:))),max(abs(log_data(:)))])
xlabel('xaxis')
ylabel('yaxis')
title('figure 2')
sgtitle({'Sample data ', ['Slice: ',num2str(slice),' index: ', num2str(idx)]},'FontSize',16,'FontWeight','Bold')
h.slider1=uicontrol('Parent',h.f,...
'Units','Normalized',...
'Position',[0.1 0.06 0.8 0.05],...
'Style','slider',...
'SliderStep',[1,sampling],...
'Min',1,'Max',nslice,'Value',1,...
'Callback',{#slider_Callback,data,x_axis,y_axis});
txt1 = 'Slice';
txt2 = 'Index';
annotation('textbox', [0.05 0.07 0.05 0.04], 'string', txt1);
annotation('textbox', [0.05 0.021 0.05 0.04], 'string', txt2);
h.slider2=uicontrol('Parent',h.f,...
'Units','Normalized',...
'Position',[0.1 0.02 0.8 0.05],...
'Style','slider',...
'SliderStep',[1,1],...
'Min',1,'Max',nidx,'Value',1,...
'Callback',{#slider_Callback,data,x_axis,y_axis});
guidata(h.f,h)
%%
function slider_Callback(hObject,eventdata,data,x_axis,y_axis)%#ok<INUSD>
h=guidata(hObject);%retrieve struct
slice_i = round(get(h.slider1, 'Value'));
idx_i = round(get(h.slider2,'Value'));
inst = squeeze(data(idx_i,:,slice_i));
colorbar;
colormap(h.ax(1),'gray')
caxis(h.ax(1),[min(abs(inst(:))),max(abs(inst(:)))])
h.ax(1) = imagesc(x_axis,y_axis,inst); colorbar
lg = log(inst);
colorbar;
colormap(h.ax(2),'jet')
caxis(h.ax(2),[-max(abs(lg(:))),max(abs(lg(:)))])
h.ax(2) = imagesc(x_axis,y_axis, lg ); colorbar;
sgtitle({'Sample data ', ['Slice: ',num2str(slice_i),' index: ', num2str(idx_i)]},'FontSize',16,'FontWeight','Bold')
drawnow
end
Other problems include:
The slider slides with a floating value which shouldnt be the case
When my data has only 1 slice, the slider moves to value zero which shouldn't happen. You can try the same example with data = rand(3,1024,64,1);
I have a figure with two or more lines. These lines have additional, important information associated with them, like how many data points were averaged to create the line etc. I would like to access this information in my figure.
I thought a good solution for this would be to if you could hover over a line with your mouse and get that extended information.
However searching for tooltips/overlays/hover-over on figures seemed to not be fruitful.
Example:
figure; hold on;
plot(1:10,rand(10,1))
plot(1:10,rand(10,1))
% additional info
plot_1_info.name = 'Alice';
plot_2_info.name = 'Bob';
plot_1_info.age = 24;
plot_2_info.age = 12;
Any good solutions or better approaches for this?
You can change the data cursor behaviour, this option has good backwards compatability (I've tested the below in R2017b, used similar before in 15b).
See my comments for details:
% Create some data
x = (1:2:20).';
y = rand(10,1);
name = { 'Alice'; 'Alice'; 'Alice'; 'Alice'; 'Bob'; 'Bob'; 'Bob'; 'Chris'; 'Chris'; 'Chris' };
age = [ 24; 24; 24; 24; 12; 12; 12; 17; 17; 17 ];
% Put it in a table, so we have it all together for indexing as plot data
tbl = table( x, y, name, age );
% Create the plot, assign the UserData property to the plot object
f = figure;
plt = plot( x, y );
plt.UserData = tbl;
% Hijack the Data Cursor update callback so we can inject our own info
dcm = datacursormode( f );
set( dcm, 'UpdateFcn', #onDataCursor );
% Function which returns the text to be displayed on the data cursor
function txt = onDataCursor( ~, evt )
% Get containing figure
f = ancestor( evt.Target, 'figure' );
% Get the index within the original data
idx = getfield( getCursorInfo( datacursormode( f ) ), 'DataIndex' );
% The original data is stored in the UserData property
data = evt.Target.UserData;
% Each element of the cell array is a new line on the cursor
txt = { sprintf( 'X: %g', data.x(idx) ), ...
sprintf( 'Y: %g', data.y(idx) ), ...
sprintf( 'Name: %s', data.name{idx} ), ...
sprintf( 'Age: %g', data.age(idx) ) };
end
Output:
Note: I've not handled anywhere the case that there is more than one data cursor tip. You can easily implement a loop over idx within the callback to handle this, I leave it as an exercise.
This approach is really flexible. For instance if we had 3 lines (one per 'person') then they can each have their own UserData struct, and we don't need to repeat all the info in table rows.
A = struct( 'X', 1:4, 'Y', rand(1,4), 'Name', 'Alice', 'Age', 24 );
B = struct( 'X', 1:3, 'Y', rand(1,3), 'Name', 'Bob', 'Age', 12 );
C = struct( 'X', 1:3, 'Y', rand(1,3), 'Name', 'Chris', 'Age', 17 );
f = figure; hold on;
plt = plot( A.X, A.Y ); plt.UserData = A;
plt = plot( B.X, B.Y ); plt.UserData = B;
plt = plot( C.X, C.Y ); plt.UserData = C;
% ... Now the struct fields can be accessed from the callback
Using the new data tip customization system introduced in R2019a, we can do the following:
figure(); hP = plot(1:10,rand(10,1),1:10,rand(10,1));
nPts = cellfun(#numel, {hP.XData});
hP(1).DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('Name', repmat("Alice",nPts(1),1) );
hP(1).DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('Age', repmat(12, nPts(1),1) );
hP(2).DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('Name', repmat("Bob", nPts(2),1) );
hP(2).DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('Age', repmat(24, nPts(2),1) );
% (Of course the above can be organized in a nicer way using a function)
Which yields:
Notice that the "hover datatip" has black text, while the "click datatip" has blue text - this is default behavior.
I am working on GUI. I want to store data in extra fields created in handles structure. However, I don't know how to update handles structure properly when callback function ends. Please, give any advice.
My simplified program
Set number of signal (1-10). Each signal has 3 parameters.
Read parameter for selected signal from array created in handles structure
(default are zeros).
Edit parameter, update the array.
GUI
function simple_gui(hObject, h)
h.fig = figure(...
'Units','pix',...
'Position',[50 50 500 400],...
'Visible','default',...
'Name','GUI',...
'NumberTitle','off',...
'Resize','on');
table = {'1' , '2', '3' , '4', '5', '6', '7', '8', '9', '10' };
h.number = uicontrol(...
'Units','characters',...
'Max',10,...
'Min',1,...
'String',table,...
'Style','popupmenu',...
'Value',1,...
'Position',[37.4 28.3846153846154 19.4 1.61538461538462],...
'BackgroundColor',[1 1 1]);
h.edit1 = uicontrol(...
'Units','pix',...
'String','0',...
'Style','edit',...
'Position',[180 280 50 20],...
'BackgroundColor',[1 1 1],...
'FontSize',10);
h.edit2 = uicontrol(...
'Units','pix',...
'String','0',...
'Style','edit',...
'Position',[180 255 50 20],...
'Children',[],...
'FontSize',10);
h.edit3 = uicontrol(...
'Units','pix',...
'String','0',...
'Style','edit',...
'Position',[180 230 50 20],...
'FontSize',10);
Main code:
h.parameter1 = zeros(1,10);
h.parameter2 = zeros(1,10);
h.parameter3 = zeros(1,10);
h.signal_no = 0;
h.number.Callback = {#number_Callback, h};
h.edit1.Callback = {#parameter_change_Callback, h};
h.edit2.Callback = {#parameter_change_Callback, h};
h.edit3.Callback = {#parameter_change_Callback, h};
guidata(h.fig, h);
function number_Callback(hObject,eventdata, h)
h = guidata(hObject);
h.signal_no = hObject.Value;
k = h.signal_no;
h.edit1.String = h.parameter1(k);
h.edit2.String = h.parameter2(k);
h.edit3.String = h.parameter3(k);
guidata(hObject,h);
function parameter_change_Callback(hObject,eventdata, h)
h = guidata(hObject);
k = h.signal_no;
h.parameter1(k) = str2double(h.edit1.String);
h.parameter2(k) = str2double(h.edit2.String);
h.parameter3(k) = str2double(h.edit3.String);
guidata(hObject, h);
In summary:
Call guidata(handleObject, varToStore) (documentation) at the end of GUI callback functions to ensure updates to one modified variable are stored. Here, handleObject is either your figure's handle or a child of it, and varToStore is the updated variable you want stored; it is often a structure.
The syntax for retrieving stored data from a figure or child handle:
handles = guidata(gcbo); % gcbo will get the callback object (instance of handle class).
handles.propToUpdate = handles.propToUpdate+1;
guidata(gcbo,handles); % stores the updated struct
In addition:
You won't see the changes from your popupmenu reflected in your edit boxes in the GUI with the current code because you are assigning the numeric values to a edit handle's String field. You call str2double() when taking values this field, and just need to do the reverse (num2str()) to get the displayable values back in. Here's the updated code with a simplified callback declaration
h.number.Callback = #number_Callback;
function number_Callback(hObject,~)
h = guidata(hObject);
h.signal_no = hObject.Value;
k = h.signal_no;
h.edit1.String = num2str(h.parameter1(k));
h.edit2.String = num2str(h.parameter2(k));
h.edit3.String = num2str(h.parameter3(k));
guidata(hObject,h);
end
I'm creating a tool for our engineering team to view data coming off our systems in the field. The underlying data isn't critical to it. Basically, it consists of vectors containing Y data at X time.
I'm plotting a series of vectors using subplot. Each plot has the ButtonDownFcn defined to launch a window that allows for deeper analysis. The problem is that when I click on the axes in the deployed application, nothing happens. There are no error messages or anything. When I click on the axes running it in Matlab, it works exactly as expected.
I'm not sure what's going on once the code is deployed that is preventing it from functioning properly. I'm a little lost on where to go. I've included my code and some sample data.
Test Data:
stats = struct('name','Car 54', ...
'date', '11-Aug-2014');
stats.SOC = struct('time', linspace(1,24,100)*3600', ...
'plugdata', [100*ones(20,1); NaN(70,1); (20:4:56)'], ...
'drivedata', [NaN(20,1); (100:-2:60)'; NaN(10,1); (40:-2:20)'; NaN(20,1); (30:-2:16)'; NaN(10,1)], ...
'eptodata', [NaN(41,1); (58:-2:40)'; NaN(11,1); (18:-2:5)'; NaN(13,1); NaN(7,1); NaN(11,1)], ...
'engchargedata', [NaN(69,1); (5:2:30)'; NaN(18,1)], ...
'otherdata', NaN(100,1));
Code:
function [output] = summarytablepopup(stats)
FH = figure('Name','Summary Table Popup', ...
'Units', 'normalized', ...
'Position', [0.05 0.05 0.9 0.8], ...
'Tag', 'sumTablePU', ...
'Toolbar', 'none', ...
'NumberTitle', 'off', ...
'WindowStyle', 'normal', ...
'Resize', 'on', ...
'CloseRequestFcn', #closereq, ...
'MenuBar', 'none', ...
'UserData', {});
movegui(FH,'onscreen')
noStats = numel(stats);
screensize = get(0,'ScreenSize');
mapIMG = imread([pwd '\icons\map.jpg']);
noGraphs = 5;
AH = NaN(noStats,1); % axes handles
TT = NaN(noStats,1); % name text handles
MB = NaN(noStats,1); % map button handles
TH = NaN(ceil(noStats/noGraphs),1); % tab handles
warning('off','all')
TGH = uitabgroup('Parent',FH); % tab group handle
for ii = 1:length(TH)
TH(ii) = uitab('parent',TGH,'title',sprintf('Page %d',ii));
end
warning('on','all')
for ii = 1:noStats
currentPage = ceil(ii/noGraphs);
vehiclename = stats(ii).name;
vehicledate = stats(ii).date;
if isfield(stats(ii),'SOC') && ~isempty(stats(ii).SOC) && isfield(stats(ii).SOC,'time') && ~isempty(stats(ii).SOC.time)
SOC = stats(ii).SOC;
time = SOC.time/3600;
subplot(5,1,mod(ii-1,noGraphs)+1,'Parent',TH(currentPage))
HH = plot(time, SOC.plugdata, 'g-x', ...
time, SOC.eptodata, 'b-x', ...
time, SOC.engchargedata, 'b-x', ...
time, SOC.drivedata, 'r-x', ...
time, SOC.otherdata, 'k-x');
AH(ii) = get(HH(1),'Parent');
set(HH,'Marker','.')
set(HH(3),'Color',[0 0.75 1])
set(HH(3),'MarkerFaceColor',[0 0.75 1])
else
subplot(5,1,mod(ii-1,noGraphs)+1,'Parent',TH(currentPage))
HH = plot([0 12 24],[NaN NaN NaN]);
AH(ii) = get(HH(1),'Parent');
%}
end
pos = get(AH(ii),'Position');
pos(1) = 0.25;
pos(3) = 0.72;
set(AH(ii),'Position',pos)
set(AH(ii),'UserData', ii)
set(AH(ii),'ButtonDownFcn', #divedeep)
set(AH(ii),'YLim',[0 100])
set(AH(ii),'YTick',[0 25 50 75 100])
set(AH(ii),'YTickLabel',{'0','25','50','75','100'})
set(AH(ii),'XLim',[0 24])
set(AH(ii),'XTick',[0 4 8 12 16 20 24])
set(AH(ii),'XTickLabel',{'0000','0400','0800','1200','1600','2000','2400'})
mapHeight = 0.1;
mappos = [0.18 pos(2)+pos(4)/2-mapHeight/2 mapHeight*screensize(4)/screensize(3) mapHeight];
MB(ii) = uicontrol('Parent', TH(currentPage), 'Style', 'pushbutton', ...
'Tag', sprintf('mapButton%d',ii), ...
'String', '', ...
'Units', 'normalized', ...
'Position', mappos, ...
'CData', mapIMG, ...
'Callback', #mapbutton);
if isfield(stats(ii),'location') && ~isempty(stats(ii).location) && isfield(stats(ii).location,'time') && ~isempty(stats(ii).location.time)
set(MB(ii),'Enable','on')
else
set(MB(ii),'Enable','off')
end
textHeight = 0.05;
textpos = [0.01 pos(2)+pos(4)/2-textHeight/2 0.15 textHeight];
TT(ii) = uicontrol('Parent', TH(currentPage), 'Style', 'text', ...
'Tag', sprintf('text%d',ii), ...
'String', vehiclename, ...
'FontSize', 12, ...
'Units', 'normalized', ...
'Position', textpos);
end
uiwait(FH)
function mapbutton(source, event)
tag = get(source,'Tag');
splittag = strsplit(tag,'n');
jj = str2num(splittag{2});
loc = stats(jj).location;
if ~isempty(loc)
len = numel(loc.time);
map = [linspace(1,0,len)', linspace(0,1,len)', zeros(len,1)];
MFH = figure;
MPH = plot(loc.lon, loc.lat, 'r:');
hold on;
MSH = scatter(loc.lon, loc.lat, 50, 'o', 'filled', 'CData', map);
plot_google_map
else
msgbox('No location information available for this vehicle. Really should disable this button.')
end
end
function electric(source, event)
ratio = get(SH,'Value')/100*(0.9-startheight)+0.05;
set(PH, 'Position', [panpos(1) ratio panpos(3) panpos(4)])
end
function divedeep(source, event)
HEDtimeplot([],stats(get(source,'UserData')));
end
function closereq(source,event)
uiresume(source)
delete(source)
end
end
I made a GUI that gets 2 elements: files (list of files) and options (I will explain later).
there is a function that calls the function below:
// asume that this is my 'options'
options{1} = {'Treatment', 't1', 't2'};
options{2} = {'Tree', '1', '2'};
options{3} = {'Replica', 'r1', 'r2', 'r3'};
// asume that this is my 'files' (may be more than 2 images
files{1} = 'C:\Documents and Settings\erezalon\Desktop\gib_proj_02.10.12\fina3_32bit\IMG_4640.JPG';
files{2} = 'C:\Documents and Settings\erezalon\Desktop\gib_proj_02.10.12\fina3_32bit\grapes03.jpg';
mydata = mainGUI(options, files).
// here I want to check 'mydata'. if it is equal to zero or not.
for each image, the GUI is created in the function 'mainGUI' (but each time, one GUI is showed till the user presses 'next').
I want to do the next thing:
if the user presses the close button in the GUI, I want to stop the displaying of the other GUI-s and set 'data = 0'. then, I will check what is the returned element ('mydata') and if it's equal to 0, I will know that the user closed the GUI and I will act as needed.
I tried to do this by the 'cmdClose_Callback' but it doesn't work.
assume that 'files' = two images, so this is the GUI of the first image.
I press the close button:
and got the GUI of the second image despite of closing the GUI of the first image.
I want that when I close the GUI, the other GUI-s don't appear.
this is my code:
function data = mainGUI(options, files)
%# current options
j = 1;
ops = cellfun(#(c) c(1), options, 'Uniform',false);
data{j} = [ops{1:length(ops)}];
j = j + 1;
options = cellfun(#(c) c(2:1:end), options, 'Uniform',false);
clear ops;
ops = cellfun(#(c) c(1), options, 'Uniform',false);
opts = [ops{1:length(ops)}];
%# create main figure, with plot and options button
hFig = figure('Name','window 1','Visible','Off');
a = 1
callback
%# options button callback function
function callback(o,e)
a = 2
%# save current options (sharing data between the two GUIs)
setappdata(hFig, 'opts',opts);
%# display options dialog and wait for it
for k=1: length(files)
hOptsGUI = secondaryGUI(hFig, options, k, length(files));
img = imread(files{k}); %# Read the data from image file data
hAxes = axes('Parent',hOptsGUI,'Units','pixels','Position',[362 242 424 359]); %# so the position is easy to define
image(img,'Parent',hAxes); %# Plot the image
set(hAxes,'Visible','off'); %# Turn the axes visibility off
a = 3
waitfor(hOptsGUI);
a = 4
%# get new options, and update plot accordingly
opts = getappdata(hFig, 'opts');
data{j} = opts;
j = j + 1;
end
end
end
function hFig = secondaryGUI(hParentFig, options, k, num_files)
%# create figure
a = 5
hFig = figure('Name','Step 3 of 4: Choose data for each image','Menubar','none', 'Resize','off', ...
'WindowStyle','modal', 'Position',[300 300 1150 600], 'CloseRequestFcn',#cmdClose_Callback);
set(gcf,'NumberTitle','off')
movegui(hFig, 'center');
options = cellfun(#(c) c(end:-1:1), options, 'Uniform',false);
num = length(options);
%# get saved settings
selected = getappdata(hParentFig, 'opts');
a = 6
%# top/bottom panels
hPanBot = uipanel('Parent',hFig, 'BorderType','none', ...
'Units','normalized', 'Position',[0 0.0 1 0.2]);
hPanTop = uipanel('Parent',hFig, 'BorderType','none', ...
'Units','normalized', 'Position',[0 0.2 1 0.2]);
%# buttongroups in top panel
hBtnGrp = zeros(1,num);
width = 1/num;
for i=1:num
%# create button group
hBtnGrp(i) = uibuttongroup('Parent',hPanTop, ...
'Units','normalized', 'Position',[(i-1)*width 0 width 1]);
%# populate it with radio buttons
height = 1./numel(options{i});
for j=1:numel(options{i})
h = uicontrol('Parent',hBtnGrp(i), 'Style','Radio', ...
'Units','normalized', 'Position',[0.05 (j-1)*height 0.9 height], ...
'String',options{i}{j});
%# set initially selected values
if strcmp(selected{i},options{i}{j})
set(hBtnGrp(i), 'SelectedObject',h)
end
end
end
if k ~= num_files
%# save button in bottom panel
uicontrol('Parent',hPanBot, 'Style','pushbutton', ...
'Units','normalized', 'Position',[0.3 0.2 0.4 0.2], ...
'String','next', 'Callback',#callback);
else
uicontrol('Parent',hPanBot, 'Style','pushbutton', ...
'Units','normalized', 'Position',[0.3 0.2 0.4 0.2], ...
'String','start', 'Callback',#callback);
end
%# save button callback function
function callback(o,e)
a = 7
%# get selected values
hObjs = get(hBtnGrp(:), 'SelectedObject');
vals = get(cell2mat(hObjs),{'String'});
%# update settings
setappdata(hParentFig, 'opts',vals);
close(hFig)
a = 8
end
function cmdClose_Callback(hObject,varargin)
disp(['Close Request coming from: ',get(hObject,'Type')]);
a = 9
%do cleanup here
delete(hFig);
a = 10
end
end
if 'files' has two images, I push the 'next' button for the first figure, and in the second figure I close, I get:
a = 1
a = 2
a = 5
a = 6
a = 3
a = 7
Close Request coming from: figure
a = 9
a = 10
a = 8
a = 4
a = 5
a = 6
a = 3
Close Request coming from: figure
a = 9
a = 10
a = 4
above the line: hOptsGUI = secondaryGUI(hFig, options, k, length(files));
I tried to put some lines. In order to testthe lines, I print a fit message:
if (ishandle(hFig))
disp('exists');
else disp('was closed');
end;
but it doesn't work :/
for each GUI that the user will close, the next callback will called:
function callback(o,e)
%# get selected values
hObjs = get(hBtnGrp(:), 'SelectedObject');
vals = get(cell2mat(hObjs),{'String'});
%# update settings
setappdata(hParentFig, 'opts',vals);
%# close options dialog
close(hFig)
end
so I just need to know in the next 'for loop' if this callback was called:
for k=1: length(files)
how can I do that?
Just check to see if hFig1 is a valid handle before you create the second figure.
if ishandle(hFig1)
hFig2 = figure(...)
else
return; % do something else
end
Repeat as needed.
function data = mainGUI(options, files)
% ...
% create main figure, with plot and options button
hFig = figure('Name','window 1','Visible','Off');
complete = callback;
if complete == 1
data = data;
else
data = 0;
end
% options button callback function
function complete = callback(o,e)
%save current options (sharing data between the two GUIs)
setappdata(hFig, 'opts',opts);
% display options dialog and wait for it
complete = 0;
for k = 1 : length(files)
hOptsGUI = secondaryGUI(hFig, options, k, length(files));
% ...
end
% we reached the end of the loop!
complete = 1;
end
I succeeded!
I used setappdata and getappdata in order to know if the second callback was called.
#Derek, Derek, thank you very much for your help and that you spent a lot of time for me!
function data = mainGUI(options, files)
%# current options
j = 1;
ops = cellfun(#(c) c(1), options, 'Uniform',false);
data{j} = [ops{1:length(ops)}];
j = j + 1;
options = cellfun(#(c) c(2:1:end), options, 'Uniform',false);
clear ops;
ops = cellfun(#(c) c(1), options, 'Uniform',false);
opts = [ops{1:length(ops)}];
%# create main figure, with plot and options button
hFig = figure('Name','window 1','Visible','Off');
callback
%# options button callback function
function callback(o,e)
%# save current options (sharing data between the two GUIs)
setappdata(hFig, 'opts',opts);
%# display options dialog and wait for it
for k=1: length(files)
hOptsGUI = secondaryGUI(hFig, options, k, length(files));
img = imread(files{k}); %# Read the data from your image file
hAxes = axes('Parent',hOptsGUI,'Units','pixels','Position',[362 242 424 359]); %# so the position is easy to define
image(img,'Parent',hAxes); %# Plot the image
set(hAxes,'Visible','off'); %# Turn the axes visibility off
out = 'FALSE';
setappdata(hFig,'some_var',out);
% show the images
%%Im = imread(files{k});
%%AxesH = axes('Units', 'pixels', 'position', [0.5, 10, 400, 260], 'Visible', 'off');
%%image('Parent', AxesH, 'CData', Im); %# add other property-value pairs as needed
waitfor(hOptsGUI);
some_other_var = getappdata(hFig,'some_var');
if (strcmp(some_other_var, 'OK') == 1)
%# get new options, and update plot accordingly
opts = getappdata(hFig, 'opts');
data{j} = opts;
j = j + 1;
else
k = length(files);
data = 0;
return;
end;
end
end
end
function hFig = secondaryGUI(hParentFig, options, k, num_files)
%# create figure
hFig = figure('Name','Step 3 of 4: Choose data for each image','Menubar','none', 'Resize','off', ...
'WindowStyle','modal', 'Position',[300 300 1150 600]);
set(gcf,'NumberTitle','off')
movegui(hFig, 'center');
options = cellfun(#(c) c(end:-1:1), options, 'Uniform',false);
num = length(options);
%# get saved settings
selected = getappdata(hParentFig, 'opts');
%# top/bottom panels
hPanBot = uipanel('Parent',hFig, 'BorderType','none', ...
'Units','normalized', 'Position',[0 0.0 1 0.2]);
hPanTop = uipanel('Parent',hFig, 'BorderType','none', ...
'Units','normalized', 'Position',[0 0.2 1 0.2]);
%# buttongroups in top panel
hBtnGrp = zeros(1,num);
width = 1/num;
for i=1:num
%# create button group
hBtnGrp(i) = uibuttongroup('Parent',hPanTop, ...
'Units','normalized', 'Position',[(i-1)*width 0 width 1]);
%# populate it with radio buttons
height = 1./numel(options{i});
for j=1:numel(options{i})
h = uicontrol('Parent',hBtnGrp(i), 'Style','Radio', ...
'Units','normalized', 'Position',[0.05 (j-1)*height 0.9 height], ...
'String',options{i}{j});
%# set initially selected values
if strcmp(selected{i},options{i}{j})
set(hBtnGrp(i), 'SelectedObject',h)
end
end
end
if k ~= num_files
%# save button in bottom panel
uicontrol('Parent',hPanBot, 'Style','pushbutton', ...
'Units','normalized', 'Position',[0.3 0.2 0.4 0.2], ...
'String','next', 'Callback',#callback);
else
uicontrol('Parent',hPanBot, 'Style','pushbutton', ...
'Units','normalized', 'Position',[0.3 0.2 0.4 0.2], ...
'String','start', 'Callback',#callback);
end
%# save button callback function
function callback(o,e)
out = 'OK';
setappdata(hParentFig,'some_var',out);
%# get selected values
hObjs = get(hBtnGrp(:), 'SelectedObject');
vals = get(cell2mat(hObjs),{'String'});
%# update settings
setappdata(hParentFig, 'opts',vals);
%# close options dialog
close(hFig)
end
function cmdClose_Callback(hObject,varargin)
%do cleanup here
delete(hFig);
end
end
There is no call to close the figure from the first GUI.
You may want to add a call close(hFig) to the end of the mainGUI function.