Updating handles from within Position Changed Callback

1 view (last 30 days)
I have defined an impoint roi object inside of an axis. I've set up the impoint with a callback for position changed function, and in that function I change the position of a second impoint as follows:
function positionChanged(pos)
handles = guihandles;
pointMoved = gco; %moving point is currently selected object
...
kids = get(pointMoved,'Children');
kids2 = get(correspondingPoint,'Children');
set(kids2(1),'Position',get(kids(1),'Position'));
set(kids2(1),'String',get(kids(1),'String'));
set(kids2(2),'XData',get(kids(2),'XData'));
set(kids2(2),'YData',get(kids(2),'YData'));
set(kids2(3),'XData',get(kids(3),'XData'));
set(kids2(3),'YData',get(kids(3),'YData'));
I'm just trying to get correspondingPoint to have the same values and positions as the point generating the callback, and the above works pretty well for this. The problem is that upon moving or resizing my figure window, all of those set values (minus the 'String' property, for some reason) revert, and my second impoint goes back to the position it had before the callback.
  2 Comments
Sean de Wolski
Sean de Wolski on 15 Jul 2014
My guess is that it's the gco. Can you get the handle from somewhere else?
Stephen
Stephen on 16 Jul 2014
Hrm... now that I think about it you may be right, but I am not sure how I would go about getting that another way. I have an arbitrary number of points defined at runtime, so each of them would execute the same callback. The way MATLAB handles the interrupt I have no way of controlling the input arguments to see which point is responsible for the callback. Anyone have any ideas?

Sign in to comment.

Accepted Answer

Alfonso Nieto-Castanon
Alfonso Nieto-Castanon on 15 Jul 2014
Your figure might have a resizefcn callback that could be reverting those values. Check:
get(gcf,'resizefcn');
  7 Comments
Alfonso Nieto-Castanon
Alfonso Nieto-Castanon on 17 Jul 2014
Edited: Alfonso Nieto-Castanon on 17 Jul 2014
I would do something like this:
f = impoint(gca,handles.lastPoint{1},handles.lastPoint{2});
setColor(f,color);
pos = getPosition(f);
setString(f,[num2str(pos(1)) ', ' num2str(pos(2))]);
%duplicate on the filtered axis
f2 = impoint(handles.axFiltered,handles.lastPoint{1},handles.lastPoint{2});
setColor(f2,color);
pos2 = getPosition(f2);
setString(f2,[num2str(pos2(1)) ', ' num2str(pos(2))]);
%ensure string gets updated if user interactively moves point
addNewPositionCallback(f,@(varargin)positionChanged(f,f2));
addNewPositionCallback(f2,@(varargin)positionChanged(f2,f));
The last two lines are the ones being modified. I am using that syntax to pass the impoint objects to the positionChanged function. Then you could have the function positionChanged something like:
function positionChanged(f1,f2)
pos=getPosition(f1);
setPosition(f2,pos);
end
And that will keep both impoint object positions "locked". Also note that if you have many impoint objects that want similarly locked (in pairs), you can just have one single positionChanged function that serves all of these, and define during the addNewPositionCallback call the appropriate parameters to pass to this function for each pair of impoint objects. Does this make sense?
Stephen
Stephen on 17 Jul 2014
Edited: Stephen on 17 Jul 2014
Yes, that makes sense and works well! I tried it out on a copy of my code, and seems to do it. That's a neat trick to be able to cast varargin. Much appreciated! I was also able to hack my way through the problem as in the answer below, but this is much simpler.

Sign in to comment.

More Answers (1)

Stephen
Stephen on 17 Jul 2014
While I did not solve the problem, I did come up with a work-around which does what I need, in case anyone comes after me has the same issues. I've found that if you first change the position of an impoint object inside of the callback as done in the original question, and then go through and create new impoint objects in their place, the changed position is stable so long as you're careful to keep the handles.impoint array updated. Here is the code inside of the position changed callback which does that, by iterating through the handles.impoints array:
handles = guihandles;
for i = 1:length(handles.impoint)
currentPoint = handles.impoint(i);
kids = get(currentPoint,'children');
%save everything to put into new point
x = get(kids(3),'XData');
y = get(kids(3),'YData');
string = get(kids(1),'String');
axis = get(currentPoint,'parent');
userData = get(currentPoint,'UserData');
color = get(currentPoint,'children');
color = get(color(2),'Color');
%don't overwrite the currently moving point
if i == pointMovedIdx
continue;
end
%otherwise, remake the point
h = impoint(axis,x,y);
setString(h,string);
setColor(h,color);
%add the correct callback based on which axis it's in
if axis == handles.axFiltered
%it's in axFiltered
addNewPositionCallback(h,@positionChangedFiltered);
%get the double handle
han = get(handles.axFiltered,'children');
han = han(1);
else
%it's in axUnfiltered
addNewPositionCallback(h,@positionChangedUnfiltered);
han = get(handles.axUnfiltered,'children');
han = han(1);
end
set(han,'UserData',userData);
handles.impoint(i) = han;
delete(currentPoint);
end
  1 Comment
Stephen
Stephen on 17 Jul 2014
Also, see the answer above for a much simpler solution thanks to Alfonso!

Sign in to comment.

Categories

Find more on Just for fun in Help Center and File Exchange

Tags

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!