MATLAB: Mouse click on Axes Problem

axesaxes1_buttondownfcnmouse

Hello. I am trying to use the mouse click on an axes to drive the position of an xystage. I have created my a grid with identifying text:
axes(handles.axes1); cla reset
hold on
ax = gca;
ax.XGrid = 'on';
ax.YGrid = 'on';
xticks(1:1:13)
yticks([1:1:9])
xlim([1 13]);
ylim([1 9]);
ax.GridColor = [0 .5 .5];
ax.GridLineStyle = '--';
ax.GridAlpha = 0.5;
ax.Layer = 'top';
hold on;
format bank
startingRows = linspace(1, 8, 8);
startingCols = linspace(1, 12, 12);
% % Now get the starting integer rows / cols.
startingRows = int32(startingRows(1:end))
startingCols = int32(startingCols(1:end))
ct=0;
for i=1:length(startingRows)
for j=1:length(startingCols)
ct=ct+1;
%Add region number
xr=double(startingCols(j))+0.3;
yr=double(startingRows(i))+0.5;
hold on
text(xr,yr,[num2str(i),',',num2str(j)],'FontSize', 8, 'Color', [1 0 1]);
end
end
set(handles.axes1,'Visible','on');
set(handles.axes1,'ButtonDownFcn',@ImageClickCallback); %An alternative to axes ButtonDownfunction
I then want to be able to click anywhere on the grid and return the number sin the grid. Its fine just to return the coordinates of the mouse. I have tried the axes1 ButtondownFunction via:
axes(handles.axes1)
cpt = get(gca,'CurrentPoint')
pt = cpt(1,1:2)
x=round(pt(1))
y=round(pt(2))
But it only works before the grid and numbers are drawn on. I have read this only works when actually clicking on the grid and not areas inside i.e. the boxes – which is what I want.

Best Answer

It is prone to bugs to rely on the current axes object by cla and gca. You have the handle of the axes available, so use it. Replace:
axes(handles.axes1); cla reset
hold on
ax = gca;
by
ax = handles.axes1;
cla(handles.axes1, 'reset')
ax.NextPlot = 'add'; % EDITED, was 'on'
The format bank influences all following output to the command window. It is not useful here.
Replace
startingRows = linspace(1, 8, 8);
startingRows = int32(startingRows(1:end))
by the much simpler:
startingRows = 1:8;
(1:end) can be omitted at all, because it wastes time only.
I assume, the only problem with your code is, that the text objects shadow the axes, such that a click on them does not trigger the ButtonDownFcn of the axes in the background. You can let the text objects pass through the event by setting their 'HitTest' to 'off':
text(xr, yr, sprintf('%d,%d', i, j), 'FontSize', 8, 'Color', [1 0 1], ...
'HitTest', 'off');
Summary:
% ** UNTESTED CODE - WRITTEN IN THE FORUMS INTERFACE ONLY **
ax = handles.axes1;
cla(ax, 'reset')
ax.NextPlot = 'on'; % Equivalent to: hold on
ax.XGrid = 'on';
ax.YGrid = 'on';
ax.XTick = 1:13;
ax.YTick = 1:9;
ax.XLim = [1 13];
ax.YLim = [1 9];
ax.GridColor = [0 .5 .5];
ax.GridLineStyle = '--';
ax.GridAlpha = 0.5;
ax.Layer = 'top';
for i = 1:8
for j = 1:12
text(j + 0.3, i + 0.5, sprintf('%d,%d', i, j), ...
'FontSize', 8, 'Color', [1 0 1], ...
'HitTest', 'off');
end
end
ax.Visible = 'on';
ax.ButtonDownFcn = @ImageClickCallback;
And the callback:
function ImageClickCallback(AxesH, EventData)
cpt = get(AxesH, 'CurrentPoint');
pt = cpt(1, 1:2);
x = round(pt(1));
y = round(pt(2));
... what to do with x and y?
end
Using the dot notation "ax.Property = ..." only looks nicer, but is is no error to mix it with "set(ax, 'Property', ...)" and the more abstract functions like xticks and hold on.