Updating handles from within Position Changed Callback

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 commentaires

My guess is that it's the gco. Can you get the handle from somewhere else?
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?

Connectez-vous pour commenter.

 Réponse acceptée

Your figure might have a resizefcn callback that could be reverting those values. Check:
get(gcf,'resizefcn');

7 commentaires

I just checked, and unfortunately there is no resize function for my figure
I will let others more familiar with impoint answer this but you might need to use the impoint object method setPosition to change the position of your point instead of doing this "manually"...
I would love to use that function, but Matlab does not recognize the handle within the callback as an instance of impoint. Instead, it is treating the handle to impoint as a double and lets me know it can't find a function setPosition that takes a double. That's why I was going through all of the trouble of moving the children individually.
Likely the callback handle is to the point rather to the impoint object. Perhaps storing the handle returned by impoint and using that instead would work? (If you post the code used to create your impoint objects and set the corresponding callbacks perhaps I can give you a more precise suggestion)
I see what you're saying. Here is the code that generates the impoints:
f = impoint(gca,handles.lastPoint{1},handles.lastPoint{2});
setColor(f,color);
pos = getPosition(f);
setString(f,[num2str(pos(1)) ', ' num2str(pos(2))]);
%ensure string gets updated if user interactively moves point
addNewPositionCallback(f,@positionChangedUnfiltered);
%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))]);
addNewPositionCallback(f2,@positionChangedFiltered);
What I tried doing is adding these lines after every impoint definition:
impoints{1,end+1} = f;
impoints{1,end+1} = f2;
set(handles.axUnfiltered,'UserData',impoints);
And then I get impoints out inside of the callback:
impoints = get(handles.axUnfiltered,'UserData');
getPosition(impoints{1,2});
This gets me the error: reference to invalid or deleted object. For some reason, all of the objects in impoints are "deleted impoint objects".
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 le 17 Juil 2014
Modifié(e) : Stephen le 17 Juil 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.

Connectez-vous pour commenter.

Plus de réponses (1)

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 commentaire

Also, see the answer above for a much simpler solution thanks to Alfonso!

Connectez-vous pour commenter.

Catégories

En savoir plus sur Creating, Deleting, and Querying Graphics Objects dans Centre d'aide et File Exchange

Tags

Community Treasure Hunt

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

Start Hunting!

Translated by