In this post,Matlab: How to get the current mouse position on a click by using callbacks , it shows something as follows:
function mytestfunction()
f=figure;
set(f,'WindowButtonDownFcn',#mytestcallback)
function mytestcallback(hObject,~)
pos=get(hObject,'CurrentPoint');
disp(['You clicked X:',num2str(pos(1)),', Y:',num2str(pos(2))]);
However, I cannot get the pos and use it in mytestfunction().
could anyone help ? Thanks !
If you are not using GUIDE and hence do not have the handles structure (see bottom), you can utilize the UserData property of the figure to pass any information:
set(gcf,'UserData',pos);
Then you can access pos from anywhere else via:
pos = get(gcf,'UserData');
See this MathWorks description of the UserData property, and this full example. From the first page:
All GUI components, including menus and the figure itself have a UserData property. You can assign any valid MATLAB workspace value as the UserData property's value, but only one value can exist at a time.
As a workaround to this limitation, you could assign a struct to UserData that has all the properties needed by your program stored in different fields.
A detail I left out in the commands above is the figure/object handle (you probably don't actually want to use gcf). In mytestfunction you have it stored in f. In the callback you can find the parent figure of the hObject by:
f = ancestor(hObject,'figure');
One way to use the above approach is to simply wait for changes in the UserData property:
function mytestfunction()
f=figure; set(f,'WindowButtonDownFcn',#mytestcallback)
maxPos=10; cnt=0;
while cnt<maxPos, waitfor(f,'UserData'); pos=get(gcf,'UserData'), cnt=cnt+1; end
function mytestcallback(hObject,~)
pos=get(hObject,'CurrentPoint');
set(ancestor(hObject,'figure'),'UserData',pos);
Note that another way to handle events is to implement a listener to respond to the clicking event, but the WindowButtonDownFcn callback should work fine.
Originally, I was thinking GUIDE, in which you would have the handles structure. This is one purpose of the handles structure. Store the position in a field of handles, and update it:
handles.pos = pos; % store it
guidata(hObject,handles); % update handles in GUI
Then back in mytestfunction or whatever other callback needs access to pos, you can use handles.pos, if the handles structure is up to date.
Related
I have a simple GUI where I want to use a text field to display a constantly changing value generated in a loop. I just don't now how to get it working. From the help files and some forum thread I have the following:
First I create my text object:
hTimer = uicontrol('Style','text','String','Time',...
'Position',[450,300,60,15],...
'Callback',#Timer_CreateFcn);
I create some function:
function Timer_CreateFcn(hObject, eventdata, handles)
global statText
statText = hObject;
end
and then I have have my loop where the values are generated:
while ...
textString=['TestCycleTime = ',num2str(datestr(tsNum(idx-5)-tsNumDoor(1),'MM:SS.FFF')),' [Min:Sec]'];
global statText;
set(statText, 'String', textString);
end
The script is running without errors, but still the timer is not updating.
Could someone please give me a hint?
The issue is that you are updating the 'String' property of your text object within a while loop which prevents MATLAB from automatically taking the time to actually render the change. To alter this behavior, you can explicitly call drawnow after settings the 'String' property to explicitly render the current figure.
set(hTimer, 'String', textString);
drawnow
As a side-note, I would recomment looking into the ways to pass data around your app rather than using global variables.
I have being to share data between several callback options in Matlab, however no succes so far. I have a gui with multiple tables which I use to get the input from the user. I have multiple callback functions for the different tables. I would like to use the data from table 1 and callback 1 together with the date in table 2 in callback two.
function MaterialProperties(Material, Data)
Material_data = get(Material, 'Data');
% Avoid bluehighlight in table
set(Material,'Data',{'dummy'});
set(Material,'Data', Material_data);
% Store variable in workspace
assignin('base','Material_data',Material_data)
%Mat_data = guidata(gcbo);
%for i=1:size(Material_data,2)
% Mat_data.MatData{i}=Material_data{i};
%end
% Save the change you made to the structure
guidata(gcbo,Mat_data)
assignin('base','Mat_data',Mat_data)
end
function Stacking_sequence(Layup, Data)
% I want to use the date (Material_data) of MaterialProperties here in this callback
layup_data = get(Layup, 'Data');
%overwrite data with a dummy and restore the old data afterwards, to force deselection
set(Layup,'Data',{'dummy'});
set(Layup,'Data', layup_data );
%store variable in workspace
assignin('base','layup_data',layup_data)
layup = strsplit(layup_data{1,1},'\');
assignin('base','layup',layup)
end
Can anyone help. I tried theMatlab help, but the suggestions stated there didn't work (maybe I implemented it wrong)
It looks like you simply need to retrieve the handles structure at the beginning of callback 2, like you did in the first callback:
Mat_data = guidata(gcbo);
after which it should be available in the 2nd callback. By the way this very line and the 3 lines following it are commented in your code is that a mistake?
Alternative solution:
As an alternative solution, you can use setappdata/getappdata to share data between function callbacks as well as in the command window, depending on where you store those data.
For example, if you save Material_data at the end of the 1st callback using something like this:
setappdata(0,'MatData',Material_Data); % Save in the Matlab root 0 (accessible everywhere), and give some dummy name)
Then at the beginning of the 2nd callback, you can retrieve the data using getappdata:
Material_Data = getappdata(0,'MatData');
and you're good to go. Instead of using the 0 root, you could also store the data in the GUI itself, using for example handles.FigureGUI or whatever the name of the figure is. Then the data would be available only if the figure is not closed/deleted. Play around with those and see what you prefer.
Hope that helps!
I created an UItable in Matlab which I fill with various values and options.
It looks like:
the corresponding code is the following:
selector_1 = { 'A'; 'B' ; 'C' };
selector_2 = { 'A.1'; 'A.2'; 'A.3'; ...
'B.1'; 'B.2'; 'B.3'; ...
'C.1'; 'C.2'; 'C.3' };
rows = 5;
f = figure('name','Configuration of output','Position',[200 200 430 25+rows*20],'numbertitle','off','MenuBar','none');
dat = {'select outputfile...', 'select identifier...', 'Specifier', 'Index'};
dat = repmat(dat,rows,1);
columnname = {'Output file ',...
'Identifier ',...
'Specifier ', 'Index'};
columnformat = { {selector_1{:}}, {selector_2{:}}, 'char', 'numeric' };
columneditable = [true true true true];
t = uitable('Units','normalized','Position',...
[0 0 1 1], 'Data', dat,...
'ColumnName', columnname,...
'ColumnFormat', columnformat,...
'ColumnEditable', columneditable,...
'RowName',[]);
set(t, 'Data', dat,'celleditcallback','get(t,''Data'')');
So I run the code and the figure is open. The underlying script has therefore finished.
When I now edit the table my uitable object is changed and after I finished I can get my final configuration with:
finalconfig = get(t,'Data');
But the thing is I need manually type this line, because my script has already finished. If I put this line at the end of my script, I get an error.
So I thought about using the following loop, to detect when I close the table and to store the last configuration
while ~isempty(findobj('name','Configuration of output'))
% some action
end
finalconfig = get(t,'Data');
And I tried everything to put inside the loop, the whole script, just the set command including the celleditcallback, and other things, but nothing worked. Either my script get stucked inside the loop or the display of my table is not updated when I edit a value. I also tried drawnow at different positions. How one handles this situation? How can I automatically store my final results?
I assume "closing the window" is the best action to detect, as I don't think I could implement a "save" button. I also tried to create a gui using GUIDE but got completely lost, I hope to solve it without.
Edit:
I was now able to implement a "save"-button and tried the callback as follows:
uimenu('Label','Save configuration','Callback',#saveConfig);
function saveConfig(~,~)
output = get(t,'Data',);
save([pwd 'output.mat'],'output');
end
also I implemented a custom CloseRequestFcn as suggested by Lucius Domitius Ahenobarbus. But then I have either one of the following problems:
1)
I define everything as a script, everything works fine, but I need to define functions like #saveConfig (actually my favorite) or #my_Closefcn as a unique function-file in my workspace and I have a hard time to pass the right parameters as dat always remains the same, even though it actually gets changend.
(The example from the mathworks site works! But it doesn't need additional parameters.)
2) When I use
function configuration
% my script from above
end
I can implement #saveConfig or #my_Closefcn directly (nested) and I guess the passing of the parameters would work fine. But the editing of my table does not work anymore, throwing the following error:
Error using handle.handle/get
Invalid or deleted object.
Error while evaluating uitable CellEditCallback
How to solve that?
Now that I know that I can even add buttons to an uitable I REALLY like to avoid GUIDE.
My code above is executable, so I'd be glad if you try it to see what my actual problem is, as it is hard to describe.
depending on using GUIDE or not:
use the CloseRequestFcn->
without GUIDE use:
%write your own CloseRequestFcn and set the figure CloseRequest-Callback to it:
set(gcf,'CloseRequestFcn',#my_closefcn)
%use gcf or the handle of the figure directly
and define my_closefcn including a delete statement for the figure-handle, else the figure will not close :)
See the docs for more information about "Redefining the CloseRequestFcn".
with GUIDE:
you can edit the CloseRequestFcn by inspecting the figure. There is a field called CloseRequestFcn that will create the function automatically and you dont need to take care about getting the handle. It will look like this:
function figure1_CloseRequestFcn(hObject, eventdata, handles)
% hObject handle to figure1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hint: delete(hObject) closes the figure
delete(hObject);
Now BEFORE deleting the figure, you should be able to get the data of the uitable (if you have the handle) and I would suggest to just assign the data to the base workspace, like:
assignin('base', 'finalTableData', get(myTableHandle,'Data'));
EDIT
as I was not clear enough, see this example:
(use within one single script)->
function test
h=figure;
x=1:10;
mytable=uitable(h,'Data',x);
set(h,'CloseRequestFcn',#myCloseFcn)
%give a unique Tag:
set(h,'Tag', 'myTag')
set(mytable,'Tag','myTableTag')
end
function myCloseFcn(~,~)
myfigure=findobj('Tag','myTag');
myData=get(findobj(myfigure,'Tag','myTableTag'),'Data')
assignin('base','myTestData',myData)
delete(myfigure)
end
in fact, there is no need to take care for the parameters of your Closereq-Callback, if you know how to find the handle of the figure! Just give something to your figure/uitable that you are able to identify it later on. I used 'Tag', because the first thing I would think of, but there would be other parameters as well.
There are only two differences I can think of between running the code directly after the code, or inside the code.
1. Scope
Perhaps you are actually working with functions, rather than scripts. In this case the problem may be that inside your function, something you need is out of scope.
2. Timing
Though it is rare, sometimes the computer may seem to be finished, whilst it is actually still busy (for a few milliseconds or so).
Here are the steps to a general approach:
Make sure there is a trivial line at the place where you want to insert your command (1==1 for example)
Put a breakpoint at the line
Once matlab stops at the breakpoint, wait a second and try to run your command.
If it works I would bet on problem number 2. try placing a pause(1) before your command and see whether it helps.
If it doesn't work you are likely meeting problem number 1. Now it becomes a matter of finding the right place to put your command. And if the command cannot be put somewhere else in the code, perhaps try an ugly evalin(,'base'). However, the latter should really be considered a workaround rather than a solution.
I have a uitable in MATLAB and currently I have callback functions to every cell.
I have been trying for a while now to set a callback to the column and row name, but with no success. More specifically if the user clicks on a particular column name, is it possible to call a function?
Please let me know if you need any more info... I would appreciate any help.
Thanks in advance!
First of all, you have to register callback to table header object. It is JTableHeader object, and you can access with findjobj function.
I created demo for registering callback function for column name click event.
This callback function is used to modify the clicked column name. It is tested on Matlab R2015a.
To run this demo, download findjobj file, and put in the same folder. Then run below code.
function TableDemo()
% Demonstration of clickable columnname.
% In this example, we use the click event to modify column name.
figure('menubar','none','numbertitle','off', 'Name', 'DEMO');
myTable = uitable('Data', magic(4), 'ColumnName',{'A','B','C','D'}, 'ColumnWidth',{50});
% Accessing underlying java object.
jscrollpane = findjobj(myTable);
jtable = jscrollpane.getViewport.getView;
jheader= jtable.getTableHeader(); % Here, you got JTableHeader object.
h=handle(jheader, 'callbackproperties');
% Set a matlab function as MouseClickedCallback
set(h, 'MouseClickedCallback', {#onHeaderClick, jtable, myTable});
end
function onHeaderClick(src, evt, jtable, hTable)
if(get(evt, 'ClickCount') > 1)
disp('header double clicked');
% Get view index from current mouse point, and convert it to
% model index. Then add 1 because Matlab index starts from 1.
index = jtable.convertColumnIndexToModel(src.columnAtPoint(evt.getPoint())) + 1;
prompt={'Column Name'};
title='Enter column names';
numLines=1;
defaultAnswer=hTable.ColumnName(index);
options.Resize='on';
options.WindowStyle='modal';
newName=inputdlg(prompt,title,numLines,defaultAnswer,options);
if ~isempty(newName)
hTable.ColumnName(index) = newName;
end
end
end
This seems to be impossible using only the standard MATLAB interface to uitable.
However, you can access the underlying Java JTable as described on undocumentedmatlab.com. Using the JTable instance you should be able to install an appropriate event handler, see this question on SO and this other article on undocumentedmatlab.com.
So, I figured out how to call one gui from another and send back and forth information via varargin and varargout. However, right now I'm in a situation where I have two separate guis (one is not called from the other), and I believe I need some other method if I want to communicate between them.
More exactly, I'm making two GUIs that interact with Simulink. One GUI opens when the model is opened and keeps track of information. The other GUI will open when a block is double-clicked. I want to send information from this GUI to the information-tracking GUI.
So, from what I've searched, I can accomplish this either by using a Listener in the information-tracking GUI; or I can modify the variables in the information-tracking GUI directly using setappdata/getappdata or findall(0, ...).
So far my attemps haven't worked and I was wondering if I'm taking the write approach. Can someone point me in a direction? Let me know if I can provide more info!
I use the setappdata/getappdata method all the time for this sort of thing. Here is a general breakdown of what you do. When you create the figures give them a tag like this:
figure( ..., 'Tag', 'info_gui', ... ); % tag name is up to you
figure( ..., 'Tag', 'other_gui', ... ); % tag name is up to you
Anytime you need the handle to one or the other figures just make a call to findobj like this
info_gui_handle = findobj('tag','info_gui');
other_gui_handle = findobj('tag','other_gui');
Ok now lets store some example data in the info_gui that we will update later
info_gui_data.x = 1;
info_gui_data.y = 1;
setappdata( info_gui_handle, 'info_gui_data', info_gui_data);
Once you have your figures set up you can do things like this:
% First you get a handle to the info gui figure
info_gui_handle = findobj('tag','info_gui');
% Next you get the appdata thats stored in this figure. In this example
% I have previously stored a struct variable called
% 'info_gui_data' inside the appdata of the info_gui
info_gui_data = getappdata(info_gui_handle ,'info_gui_data');
% Make your changes whatever they are. Here I am modifying variables x
% and y that are stored in the struct info_gui_data
info_gui_data.x = 2;
info_gui_data.y = 2;
% Now that I've made changes to the local variable info_gui_data I can
% now store it back into the info gui's appdata.
setappdata(info_gui_handle ,'info_gui_data',info_gui_data);
I like to store all of my figure appdata in one giant struct. Seems easier to keep track of but its up to you. Hope this helps :)
You could also try using guidata and guihandles.
Suppose the handle to GUI1 is H1. In GUI1, when you want to store data that you can retrieve later, use:
guidata(H1,data)
In GUI2, when you need the data, use:
data = guidata(H1);
Alternatively, you could store your data in the Property 'User Data' of your uicontrol object. Make sure you set the Property 'Tag' to something valid (e.g. 'mybutton'). To access this from GUI2, use:
handles = guihandles(H1);
data = get(handles.mybutton,'UserData');