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.
Related
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"
I have been able to put together the following code to find a time stamp every time space bar is pressed. However, I can't figure out a way to save the S.tm to the work space. Here is the code:
function main
S.tm = [];
S.cnt = 0;
S.fh = figure('KeyPressFcn',#youPressedSomething,...
'menu','none',...
'pos',[400 400 320 50]);
S.th = uicontrol('Style','text','Position',[10 10 300 30],...
'String','You have not hit space yet');
function youPressedSomething(varargin)
if strcmp(varargin{2}.Character,' ')
S.tm = [S.tm now]
S.cnt = S.cnt + 1;
set(S.th,'str',sprintf('You hit space %i!',S.cnt));
end
end
end
There are two main options here. You could use assignin within your function to save the data to the main workspace.
function main
S.tm = [];
S.cnt = 0;
S.fh = figure('KeyPressFcn',#youPressedSomething,...
'menu','none',...
'pos',[400 400 320 50]);
S.th = uicontrol('Style','text','Position',[10 10 300 30],...
'String','You have not hit space yet');
function youPressedSomething(varargin)
if strcmp(varargin{2}.Character,' ')
S.tm = [S.tm now]
S.cnt = S.cnt + 1;
set(S.th,'str',sprintf('You hit space %i!',S.cnt));
%// Save as "timestamps" in the base workspace
assignin('base', 'timestamps', S.tm);
end
end
end
Or a better approach would be to use waitfor to block execution of the function until the figure is closed. Then you can return S.tm just like a normal output argument
function timestamps = main()
S.tm = [];
S.cnt = 0;
S.fh = figure('KeyPressFcn',#youPressedSomething,...
'menu','none',...
'pos',[400 400 320 50]);
S.th = uicontrol('Style','text','Position',[10 10 300 30],...
'String','You have not hit space yet');
%// Wait until the figure is closed
waitfor(S.fh);
%// Save S.tm as timestamps and return
timestamps = S.tm;
function youPressedSomething(varargin)
if strcmp(varargin{2}.Character,' ')
S.tm = [S.tm now]
S.cnt = S.cnt + 1;
set(S.th,'str',sprintf('You hit space %i!',S.cnt));
%// Save as "timestamps" in the base workspace
assignin('base', 'timestamps', S.tm);
end
end
end
You can try to edit your code this way:
function[S.fh]=main()
%% Your Code
function yPS(varargin)
if...
%% Your Code
end
set(S.fh,'UserData',S.tm);
end %yPS
end %main
This should return figure handle to the workspace and keep it in memory as well. Then whenever the yPS function is called it uses shared handle S.fh to the figure and (re)sets UsedData property which is dedicated to contain, well, user data.
To use the function call it Foo=main.
get(Foo.fh,'UserData')
ans =
[]
Hit spacebar several times
>> get(AA.fh,'userdata')
ans =
1.0e+005 *
7.3645
7.3645
7.3645
Suppose vec_A, vec_B, vec_c are some matrices with random data. I want to write data to text file for every 5 min, My code as follows:
function samplegui_OpeningFcn(hObject, ~, handles, varargin)
handles.timer = timer(...
'ExecutionMode', 'fixedRate', ... % Run timer repeatedly
'Period', 300, ... % Initial period.
'TimerFcn', {#open,hObject}); % Specify callback
handles.output = hObject;
handles.vec_A=[];
handles.vec_B=[];
handles.vec_C=[];
guidata(hObject, handles);
function open_Callback(hObject, eventdata, handles) % push button to receive serial data.
cnt=0;
while 1
% Getting data from Serial Port
get_lines=fgets(handles.se) % getting data from serial port
if~isempty(get_lines)
cnt=cnt+1;
if strfind(get_lines,'T') %Parsing data
handles.vec_A=[handles.vec_A;[timet newword]];
plot(handles.vec_A(:,1),handles.vec_A(:,2:end),'r'); % plotting
% Same follows for parsing and plot vec_B and Vec_C
drawnow(); % to update the Plots
end
end
Pause(.05);
start(handles.timer); % saving the data
dlmwrite('My_sample1.txt',handles.vec_A);
dlmwrite('My_sample2.txt',handles.vec_B);
dlmwrite('My_sample3.txt',handles.vec_C);
stop(handles.timer);
end
guidata(hObject, handles);
While running my code, following error occurs:
Error while evaluating TimerFcn for timer 'timer-6'
Too many input arguments.
How to execute timer in this case to write data successfully for every five minutes or suggest any other way to do it.
You have defined your TimerFcn to be {#open, hObject} but you don't have a function named open. Instead, it is trying to call the built-in open with three input arguments (the timer object, an event object, and hObject) and this is producing the error because open only accepts one input argument.
That being said, it's not clear at all how the code that you have provided will accomplish anything close to what you want. Something like this may work better.
function samplegui_OpeningFcn(hObject, ~, handles, varargin)
handles.timer = timer(...
'ExecutionMode', 'fixedRate', ... % Run timer repeatedly
'Period', 300, ... % Initial period.
'TimerFcn', #(s,e)write_data()); % Specify callback
handles.output = hObject;
handles.vec_A=[];
handles.vec_B=[];
handles.vec_C=[];
guidata(hObject, handles);
start(handles.timer);
%// Now update your data in a loop
cnt = 0;
while true
%// Getting data from Serial Port
get_lines = fgets(handles.se)
if ~isempty(LINES)
cnt = cnt + 1;
if strfind(LINES, 'T')
handles.vec_A = [handles.vec_A; [timet newword]];
plot(handles.vec_A(:,1), handles.vec_A(:,2:end),'r');
drawnow
end
end
end
function write_data()
%// Write it to file
dlmwrite('My_sample1.txt',handles.vec_A);
dlmwrite('My_sample2.txt',handles.vec_B);
dlmwrite('My_sample3.txt',handles.vec_C);
end
end
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
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...