Using a variable from one figure in another figure in MATLAB GUI - matlab

I have a MATLAB GUI which I have created using GUI Layout Toolbox. This GUI has a primary figure. The primary figure has a push button that calls a secondary figure. There is a function called through primary figure, which access some variables from secondary figure. At The beginning of the code or till the point the secondary figure is opened, everything works fine. Once the secondary is opened, if I keep it open, the function call works fine, but if i close the secondary figure, the function call stops working.
Below is a snippet of how I have defined my variables and function calls:
S.Fig1 = figure();
S.var1 = uicontrol('parent',S.Fig1,...
'style','edit');
S.Fig2 = figure();
S.var2 = uicontrol('parent',S.Fig2,...
'style','edit');
S.var1 is associated with function call var1_call() and inside that function I am checking value for S.var2.
If the secondary figure is open, value is provided correctly, else the statement will show an error saying "invalid handle object"
Please let me know if I cannot define the two figures as I have and if I can then how can I check if the fig2 is closed after opening it once.
Thanks
Adding the below example code:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Test script to check calling of a new figure from main figure
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [] = TestCallingNewWindow()
SCR = get(0,'Screensize'); % Get screensize.
% Open Figure
S.fh = figure('numbertitle','off',...
'menubar','none',...
'units','pixels',...
'position',[SCR(3)/2-800 ,SCR(4)/2-100 , 500, 200],...
'name','TestCallingWindow',...
'resize','off');
% Create PushButtons
S.pb1 = uicontrol('style','pushbutton',...
'units','pixels',...
'position',[20 120 200 30],...
'string','Open New Window',...
'fontsize',12);
for i=1:6
S.Select(i) = uicontrol('parent',S.fh,...
'style','checkbox',...
'units','pixels',...
'position',[250 (165-((i-1)*30)) 30 20],...
'string',sprintf('%d',i),...
'enable','on',...
'fontsize',10);
S.Type(i) = uicontrol('parent',S.fh,...
'style','text',...
'units','pixels',...
'position',[300 (165-((i-1)*30)) 60 20],...
'string','Data',...
'enable','on',...
'fontsize',10);
S.TypeVal(i) = uicontrol('parent',S.fh,...
'style','edit',...
'units','pixels',...
'position',[365 (165-((i-1)*30)) 80 20],...
'string','0',...
'enable','on',...
'fontsize',10);
end
% Create the Pop-up Figure
S.popfh = figure('numbertitle','off',...
'menubar','none',...
'units','pixels',...
'position',[SCR(3)/2-200 ,SCR(4)/2-100 , 300, 200],...
'name','Pop-Up Window',...
'resize','off',...
'visible','off');
for i=1:6
S.popSelect(i) = uicontrol('parent',S.popfh,...
'style','checkbox',...
'units','pixels',...
'position',[50 (165-((i-1)*30)) 30 20],...
'string',sprintf('%d',i),...
'enable','on',...
'fontsize',10);
S.popType(i) = uicontrol('parent',S.popfh,...
'style','text',...
'units','pixels',...
'position',[100 (165-((i-1)*30)) 60 20],...
'string','Data',...
'enable','on',...
'fontsize',10);
S.popTypeVal(i) = uicontrol('parent',S.popfh,...
'style','edit',...
'units','pixels',...
'position',[165 (165-((i-1)*30)) 80 20],...
'string','0',...
'enable','on',...
'fontsize',10);
end
% Set callback functions
set(S.Select(:),'callback',{#main_call,S})
set(S.TypeVal(:),'callback',{#main_call,S})
set(S.pb1,'callback',{#pb1_call,S})
set(S.popSelect(:),'callback',{#pb1_call,S})
set(S.popTypeVal(:),'callback',{#pb1_call,S})
% Function Definitions
function [] = main_call(varargin)
[h,S] = varargin{[1,3]}; % Get calling handle and structure.
popWin = findobj('type','figure','name','Pop-Up Window');
for idx = 1:6
if(~isempty(popWin))
popenable = get(S.popSelect(idx),'Value');
else
popenable = 0;
end
if(popenable == 0)
enable = get(S.Select(idx),'Value');
if(enable == 1)
data = str2double(get(S.TypeVal(idx),'String'));
if(~isempty(popWin))
set(S.popTypeVal(idx),'string',data);
end
end
else
data = str2double(get(S.popTypeVal(idx),'String'));
end
end
end
% po-up window
function [] = pb1_call(varargin)
[h,S] = varargin{[1,3]}; % Get calling handle and structure.
set(S.popfh,{'visible'},{'on'});
for idx = 1:6
popenable = get(S.popSelect(idx),'Value');
if(popenable == 0)
enable = get(S.Select(idx),'Value');
if(enable == 1)
data = str2double(get(S.TypeVal(idx),'String'));
set(S.popTypeVal(idx),'string',data);
end
else % if popenable is 1
data = str2double(get(S.popTypeVal(idx),'String'));
end
end
end
end

How about naming your figures:
S.Fig1 = figure('name','figure1');
S.Fig2 = figure('name','figure2');
Then you can find them with findobj:
findobj('type','figure','name','figure2');
This will return the graphics handle if it is open, or be empty if it is closed. So this call will check if the figure exists:
~isempty(findobj('type','figure','name','figure2'))
sources:
How to check if a figure is opened and how to close it?
http://www.mathworks.com/help/matlab/ref/findobj.html
http://www.mathworks.com/help/matlab/ref/isempty.html
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
So I'm guessing you're getting the error on this line: set(S.popfh,{'visible'},{'on'}); in pb1_call if the figure is closed as described above. So instead of this you should have:
if ~isempty(findobj('type','figure','name','Pop-Up Window'))
set(S.popfh,{'visible'},{'on'});
else
S.popfh=figure('name','Pop-Up Window','Visible','on');
end
This is more robust and makes sure the figure is open before trying to change it's properties.

I'm not sure if I understand your problem.
I think you are going to pass some variables between functions. If so, you must use "guidata" function.
for example: you have read some data (lets name it DATA) in some call back function (name it MyFunc1) and want to use it in another one. If so, you must add these two line of code at the end of the exporting function:
function MyFunc1_Callback(hObject, eventdata, handles)
%
% BODY OF YOUR FUNCTION WHICH CREATES "DATA" VARIABLE
%
% attach DATA to handles structure
handles.DATA = DATA;
% Update handles structure
guidata(hObject,handles);
Then in the other function you can use the DATA stored in "handles" structure:
function MyFunc2_Callback(hObject, eventdata, handles)
data = handles.DATA;
...

I found the answer to my question.
I had to define the CloseRequestFcn of the two figures separately and with that I was able to control all my requirements

Related

MATLAB - AppDesigner: Interrupt a loop with GUI

I have created a GUI which computes a trajectory based on an external .m file.
When the user press the 'Calculate' button, the external .m function file gets called via the callback function of the button:
% calculateBtn button pushed function
function calculate(app)
numSteps = app.stepSlider.Value;
app.omega = app.omegaSpin.Value;
app.phid = app.phi.Value;
app.x0 = app.x0Spin.Value;
app.y0 = app.y0Spin.Value;
app.u0 = app.u0Spin.Value;
app.v0 = app.v0Spin.Value;
set(app.calculateBtn, 'Enable', 'off')
set(app.showBtn, 'Enable', 'off')
[app.Xc, app.Xi, app.C, T, f]=coriolis_traj(app.x0, app.y0, app.u0, app.v0, app.phid, numSteps);
app.fEdit.Value = num2str(f);
app.tEdit.Value = num2str(T);
set(app.calculateBtn, 'Enable', 'on')
if length(app.Xc)>1
set(app.showBtn, 'Enable', 'on')
else
set(app.showBtn, 'Enable', 'off')
end
end
The external file consists of the main loop of the computations.
while 1
% Counters
i = i + 1;
t = t + Dt;
theta = theta + Omega * Dt;
% Parcel's position
% on the inertial frame
x1 = x0 + Dt*u0;
y1 = y0 + Dt*v0;
% Parcel's position translated to the
% rotating frame
xc1 = x1*cos(theta)+y1*sin(theta);
yc1 = x1*sin(theta)+y1*cos(theta);
x(i) = x1 ; y(i) = y1;
xc(i) = xc1 ; yc(i) = yc1;
x0 = x1 ; y0 = y1;
[in] = inpolygon(xc,yc,xv,yv);
if ~in(i) > 0
break;
end
end
I want to stop the computation and clear the computed arrays when the user changes any of the values in 'Controls' panel, or when the button 'Break' is pushed.
How could I code this?
The best solution I can figure out is to bring your while loop inside your GUI callback. The inner code of your while loop can be kept on a separate, external file, but bringing in the loop will give you full control over it and will make it easier to interrupt. The only constraint is that it must be make less "tight"... it must contain a small pause (better if followed by a drawnow() call) so that the main GUI thread can have the time to process the application messages.
And here is the code of your callbacks:
% Computation Callback
function Button1_Callback(obj,evd,handles)
obj.Enable = 'off'; % disable this button
handles.Button2.Enable = 'on'; % enable the interruption button
handles.stop = false; % the control variable for interruption
while (true)
% call your external function for running a computational cycle
res = myExternalFunction(...);
% refresh the application handles
handles = guidata(obj);
% interrupt the loop if the variable has changed
if (handles.stop)
break;
end
% this allows the loop to be interrupted
pause(0.01);
drawnow();
end
obj.Enable = 'on';
end
% Interruption Callback
function Button2_Callback(obj,evd,handles)
obj.Enable = 'off'; % disable this button
handles = guidata(obj);
handles.stop = true;
end
There is no way in MATLAB to interrupt a function by another function, e.g. say programmatically injecting a CTRL-C into another running function, without modifying the to-be-interrupted function.
The closest you can get is by modifying the simulator code to regularly perform a callback. This is how I integrated by simulation code into a GUI. IMO it is a clean solution and also works with MEX files.
Think of it as a progress callback for your simulator code.
It could be regularly (e.g. every second, or at completion of the i-th step) called by the simulator with some percentage parameter to indicate the degree of completion.
If you modify the simulator code to stop simulating in case the callback returns false, you achieve what you want. At the same time this is minimum invasive in your simulator code. Supply a dummy callback and it will run stand alone.
GUI pseudocode:
function button_cancel_Callback(hObject, eventdata, handles)
global cancel_pressed;
cancel_pressed = true;
function dostop = callback( progress, handles )
<show progress>( handles.<XXX>, progress );
global cancel_pressed;
if cancel_pressed
dostop = true;
else
dostop = false;
end
function button_run_simulation_Callback(hObject, eventdata, handles)
global cancel_pressed;
cancel_pressed = false;
<simulator function>( ..., #callback, handles )
SIMULATOR pseudocode:
function <simulator function>( ..., callback, callback_param )
while ... % main loop
if ~isempty(callback) && ~callback( progress, callback_param )
error("canceled-by-user") % could also be something more elaborate
end
return "simulation completed"

Late updating function output in MATLAB - R2015b

I have the following code; this function is called from a parent script, and produces a GUI that allows the user to select a threshold parameter.
Unfortunately, the output parameter threshold is updated late. For example, the first time the function is run, irrespective of how I use the slider, it reports threshold as being empty, even if I have set thresh_final to 0.9. The next time I run the function, it immediately updates threshold as 0.9, before I can adjust thresh_final. That is, when I run the function at time t, it outputs the value of threshold as the selected value of thresh_final at time t-1.
function threshold = threshold_choose(frames,prob_mat)
global thresh_final
f1 = figure('Visible','on','pos',[100,50,800,800]);
ax1 = axes('Units','Pixels');
work_im = prob_mat(:,:,2);
normali = max(max(work_im));
work_im = work_im ./ normali;
user_choose = work_im > 0.8 ;
demoImage = mat2gray(user_choose);
imshow(demoImage)
sld = uicontrol('Style', 'slider',...
'Min',0,'Max',1,'Value',0.8,...
'Position', [200 50 300 20],...
'Callback', #thresh_change);
function thresh = thresh_change(source,~)
thresh = source.Value;
figure(f1)
user_choose = work_im > thresh ;
demoImage = mat2gray(user_choose);
imshow(demoImage)
thresh_final = thresh;
closeing = uicontrol('Style','pushbutton',...
'String','Close GUI',...
'Position',[700,20,80,80],...
'Callback', #closeAll);
end
function closeAll(~,~)
close all
end
end
threshold = thresh_final;
end
At the moment, to get around this bug, I can simply call the function, adjust the parameter, then close the GUI, and then call the function again, but close the GUI immediately, without adjusting the parameter, but this is not really practical.
I figure that this is because when I call the function, it runs the whole script, including the last line threshold = thresh_final, and then waits to run the nested functions until they are called, but I don't know how to get around this.
Any help would be much appreciated.

Update pushbutton string using counter when another pushbutton is active

I am setting the handles in the opening function:
function Select_A_B_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hObject;
handles.string = '';
new_count = 1;
set(handles.counter,'String',num2str(new_count));
if isempty(varargin)
varargin{1} = 1;
varargin{2} = 1;
end
A = {'Apple';'Orange';'Bag';'Cowboy'};
handles.pushbutton1text = A;
new_count = str2double(handles.counter.String);
handles.pushbutton1 = handles.pushbutton1text(new_count);
guidata(hObject, handles);
Then I am trying to change the handles to pushbutton1 when the pushbutton tagged as 'Next' is pushed:
function next_Callback(hObject, eventdata, handles)
current_count = str2double(get(handles.counter, 'String'));
new_count = current_count+1;
set(handles.counter,'String',new_count);
set(handles.pushbutton1,'String',get(handles.counter,'string');
guidata(hObject, handles);
I get the following error when I try to set the handles to pushbutton1:
Error using set
Conversion to double from cell is not possible.
I have tried several ways to fix the error, but no success yet. What am I doing wrong?
Here is a programmatic GUI which does what you want and is, in my opinion, much simpler to understand/debug. You can easily implement this using GUIDE; everything that comes before the pushbutton's callback can be put into the GUI Opening_Fcn.
I added comments in the code; if something is unclear please tell me.
function DisplayFruits
clear
clc
hFig = figure('Position',[200 200 300 300]);
handles.A = {'Apple';'Orange';'Bag';'Cowboy'};
handles.counter = 1;
%// Counter text
handles.CounterTitle = uicontrol('Style','text','Position',[50 200 60 20],'String','Counter');
handles.CounterBox = uicontrol('Style','text','Position',[130 200 60 20],'String','1');
%// Content of A
handles.TextTitle = uicontrol('Style','text','Position',[50 170 60 20],'String','Content');
handles.TextBox = uicontrol('Style','text','Position',[130 170 60 20],'String',handles.A{handles.counter});
%// Pushbutton to increment counter/content
handles.PushButton = uicontrol('Style','push','Position',[130 100 80 40],'String','Update counter','Callback',#(s,e) UpdateCallback);
guidata(hFig,handles);
%// Pushbutton callback
function UpdateCallback
%// Update counter
handles.counter = handles.counter + 1;
%// If maximum value possible, set back to 1.
if handles.counter == numel(handles.A)+1;
handles.counter = 1;
end
%// Update text boxes
set(handles.CounterBox,'String',num2str(handles.counter));
set(handles.TextBox,'String',handles.A{handles.counter});
guidata(hFig,handles);
end
end
Sample screenshot of the GUI:
As the user presses the button, the counter is incremented and the "content box" is updated.
Hope this helps!
As a side note, I think the error you got above was due to this command:
handles.pushbutton1 = handles.pushbutton1text(new_count);
here you assigned a string to the pushbutton but later you try to modify its String property and Matlab does not like it.

How in Matlab do changes on figure 1 with slider on figure 2?

I have some sliders on figure 1, and I have some images on figure 2. I want to do the callbacks for the sliders in a way that, when I change the sliders in figure 1 , the threshold changes and images update automatically in figure 2.
I'm using addlistener to send values for callback function. The problem is when you move slider the active figure is figure 1, and you want to do changes on figure 2.
adding some code for clarification:
M.rgbImage = imread('euhedral-mag-on-po-edge-pseudo-sub-ophitic-rl-fov-4-8mm.jpg');
[rows, columns, numberOfColorBands] = size(M.rgbImage);
F.f = figure; % This is the figure which has the axes to be controlled.
% Now create the other GUI
S.fh = figure('units','pixels',...
'position',[400 400 500 100],...
'menubar','none',...
'name','Image control',...
'numbertitle','off',...
'resize','off');
S.sl = uicontrol('style','slide',...
'unit','pix',...
'position',[60 10 270 20],...
'min',0,'max',255,'val',100,...
'callback',{#sl_call2,S},'deletefcn',{#delete,F.f});
....
lis = addlistener(S.sl,'Value','PostSet',#(e,h) sl_call3(S,F,M));
function sl_call3(S,F,M)
v = get(S.sl,'value');
figure(F.f), subplot(4, 4, 13);
M.redMask = (M.redPlane > v);
imshow(M.redObjectsMask, []);
set(S.ed(2),'string',v);
Create reference to both your figures:
f1=figure(1);
f2=figure(2);
And then when doing the callback pass f2 as a parameter.
In the callback, you'll have get the handle to the second figure.
There's various ways to do that.
You can specify the handle to the second figure at the time of callback-definition:
figure2 = ...;
addlistener(hSlider, ..., #(a,b) changeStuffOn(figure2));
Or during the callback:
function callbackFunction(hObject, evt)
% get the handle to the second figure, e.g. by a tag, or its name
fig2 = findobj(0, 'type', 'figure', 'tag', 'figure2'); %
% do whatever you want with fig2
end
The latter might be somewhat worse in performance, but e.g. has the benefit of working reliably even if figure2 was deleted and recreated and some point.
To avoid the change of focus you'll have to get rid of this line your callback:
figure(F.f)
This explicitly moves the focus to the second figure.
You'll have to use e.g. the imshow(axes_handle, ...) syntax, in order to show the image not in the "current axes".

imwrite current image on axes in MATLAB GUIDE

I have a problem in my GUI. In my opening function I defined an img_new variable to be an image I have stored.
My GUI has two axes, one displays the original image and the other one the filtered one. I have 4 filters in a panel with the 4 radiobuttons. And in the end of each one's code there's the img_new = the image created through the radiobutton filter.
Here's some code:
% --- Executes when selected object is changed in uipanel3.
function uipanel3_SelectionChangeFcn(hObject, eventdata, handles)
handles.count = handles.count + 1;
% Change filter orientation depending on which radiobutton is chosen
switch get(eventdata.NewValue,'Tag')
case 'hte'
h_te = zeros(handles.rows, handles.colums);
# code of the filter...
axes(handles.axes2);
imshow(h_te);
handles.img_new = h_te;
case 'hc'
h_c = zeros(handles.rows, handles.colums);
# code of the filter...
axes(handles.axes2);
imshow(h_c);
handles.img_new = h_c;
case 'vlr'
v_lr = zeros(handles.rows, handles.colums);
# code of the filter...
axes(handles.axes2);
imshow(v_lr);
handles.img_new = v_lr;
case 'vc'
v_c = zeros(handles.rows, handles.colums);
# code of the filter...
axes(handles.axes2);
imshow(v_c);
handles.img_new = v_c;
end
guidata(hObject, handles)
and here's the imwrite function:
% --------------------------------------------------------------------
function save_img_ClickedCallback(hObject, ~, handles)
% writing the new image
imwrite(handles.img_new, strcat('filtered_image_', num2str(handles.count), '.png'));
guidata(hObject, handles)
Here's the function to get the image to axes1 the original) and filter it to axes2 (filtered)
% --- Executes on button press in img2.
function img2_Callback(hObject, ~, handles)
% Read image 2
img = imread('./coimbra_estadio.jpg');
handles.img_d = im2double(img);
% image size
size_img = size(handles.img_d);
handles.colums = size_img(2);
handles.rows = size_img(1);
if rem(handles.rows,2) == 0
handles.row_0 = ((handles.rows/2)+1);
else
handles.row_0 = ((handles.rows/2)+0.5);
end
if rem(handles.colums,2) == 0
handles.colum_0 = ((handles.colums/2)+1);
else
handles.colum_0 = ((handles.colums/2)+0.5);
end
axes(handles.axes1);
imshow(img);
% Generate eventdata to call the radiobuttons function
eventdata_new.EventName = 'SelectionChanged';
eventdata_new.OldValue = get(handles.uipanel3,'SelectedObject');
eventdata_new.NewValue = get(handles.uipanel3,'SelectedObject');
uipanel3_SelectionChangeFcn(handles.uipanel3, eventdata_new, handles);
guidata(hObject, handles)
As you can see, in the end I call the panel function so when the image is loaded it is automatically filtered and the axes2 image changes.
The problem is when I call the save function it saves the old img_new.
If I change the radiobutton the img_new is refreshed, but if it is not changed it is not refreshed. It should be as loading an image automatically calls for the panel of radiobuttons function.
The problem is that guidata(hObject,handles); at the end of img2_Callback saves old handles object as a final gui state, updates made in uipanel3_SelectionChangeFcn are lost. You need to eitehr manually update handles after calling uipannel3_SelectionChangeFcn by putting handles = guidata(hObject,handles);
or handles=guidata(hObject);
(forgot which call to guidata updates handles, please see help for that), or simply remove the line guidata(hObject,handles); at the end of img2_callback (less safe if code is going to change later, updating handles after uipannel3_SelectionChangeFcn is safer approach...