I did an app designer GUI with two buttons and axes. The first one (LoadimageButton) is loading the pappers image and I can mark points until I press escape. The second button is printing out the point coordinates (PositionButton).
I have noticed that after pressing the two buttons I can move points in the axes and change their positions or delete them. The issue is that when I press the delete (in the context menu) I get this error after pressing the PositionButton:
Error using images.roi.Point/get
Invalid or deleted object.
Error in tempDrwPnt1/PositionButtonPushed (line 61)
positions = cell2mat(get(app.pointhandles, 'position'))
Error while evaluating Button PrivateButtonPushedFcn.
How can I refresh the app.pointhandles after deleting a point?
Code:
function LoadimageButtonPushed(app, event)
imshow('peppers.png','Parent',app.ImageAxes);
userStopped = false;
app.pointhandles = gobjects();
while ~userStopped
roi = drawpoint(app.ImageAxes);
if ~isvalid(roi) || isempty(roi.Position)
% End the loop
userStopped = true;
else
% store point object handle
app.pointhandles(end+1) = roi;
end
end
addlistener(roi,'MovingROI',@allevents);
addlistener(roi,'ROIMoved',@allevents);
app.pointhandles(1) = [];
function allevents(src,evt)
evname = evt.EventName;
switch(evname)
case{'MovingROI'}
disp(['ROI moving previous position: ' mat2str(evt.PreviousPosition)]);
disp(['ROI moving current position: ' mat2str(evt.CurrentPosition)]);
case{'ROIMoved'}
disp(['ROI moved previous position: ' mat2str(evt.PreviousPosition)]);
disp(['ROI moved current position: ' mat2str(evt.CurrentPosition)]);
end
end
end
% Button pushed function: PositionButton
function PositionButtonPushed(app, event)
positions = cell2mat(get(app.pointhandles, 'position'))
end
You could add a check within the PositionButtonPushed
function for whether or not each pointhandles
element is valid, report on it if so or remove it if not
Something like
function PositionButtonPushed(app, event)
nPts = numel(app.pointhandles);
positions = NaN(nPts,2); % array to hold positions
for iPt = nPts:-1:1 % loop backwards so we can remove elements without issue
if isvalid( app.pointhandles(iPt) )
positions(iPt,:) = get(app.pointhandles(iPt),'position');
else
% No longer valid (been deleted), remove the reference
app.pointhandles(iPt) = [];
% Also remove from the positions output
positions(iPt,:) = [];
end
end
end
I haven't got a compatible MATLAB version available right now to test this, but I am assuming the in-built function isvalid
works for Point
objects, otherwise you will have to add your own validity check. Alternatively you could try
to get the position, and do the deletion (handled by else
above) within a catch
, but I usually recommend against try
/catch
if you can check for a specific (known) issue instead.
I've often used something similar (e.g. for axes), but bundled the cleanup functionality for invalid handles into its own function. In this case it would have let you add a single function call before getting the positions of the remaining valid points.
I've also made this more condensed by using arrayfun
, but under the hood it's the same approach as the above loop:
function PositionButtonPushed(app, event )
app.checkHandleValidity(); % cleanup handles just in case
positions = cell2mat(get(app.pointhandles, 'position'));
end
function checkHandleValidity( app )
bValid = arrayfun( @isvalid, app.pointhandles ); % Check validity
app.pointhandles( ~bValid ) = []; % Remove invalid elements
end