Callback of axes in figure not being called

3 views (last 30 days)
Below is the code for a complete GUI that creates a simple figure (figure1) and an axes inside of it (axes1) . axes1 contains an image object. Do not be intimidated by the code, it is the code behind for the default figure created by MATLAB GUIDE, with a few lines added to it.
function varargout = untitled(varargin)
% UNTITLED MATLAB code for untitled.fig
% UNTITLED, by itself, creates a new UNTITLED or raises the existing
% singleton*.
%
% H = UNTITLED returns the handle to a new UNTITLED or the handle to
% the existing singleton*.
%
% UNTITLED('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in UNTITLED.M with the given input arguments.
%
% UNTITLED('Property','Value',...) creates a new UNTITLED or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before untitled_OpeningFcn gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to untitled_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help untitled
% Last Modified by GUIDE v2.5 20-Sep-2014 14:18:30
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @untitled_OpeningFcn, ...
'gui_OutputFcn', @untitled_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before untitled is made visible.
function untitled_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to untitled (see VARARGIN)
% Choose default command line output for untitled
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
%Set the child of axes1 to be an image
imageHandle = image(zeros([100 100], 'double'), 'Parent', handles.axes1, 'HitTest', 'off');
set(handles.axes1, 'HitTest', 'on');
% --- Outputs from this function are returned to the command line.
function varargout = untitled_OutputFcn(hObject, eventdata, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
% --- Executes on mouse press over axes background.
function axes1_ButtonDownFcn(hObject, eventdata, handles)
% hObject handle to axes1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
disp('axes1 buttondownfcn was called')
% --- Executes on mouse press over figure background, over a disabled or
% --- inactive control, or over an axes background.
function figure1_WindowButtonDownFcn(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)
disp('figure1 windowbuttondownfcn was called')
The callback for the buttondown event on axes1 , axes1_ButtonDownFcn , is not being called. However the callback for the buttondown event on figure1 , figure1_WindowButtonDownFcn, gets called. I understand which one should be called when.
What I do not get is why the axes1_ButtonDownFcn is not being called when I click on the surface of axes1. Why is it not being called? Now, similar questions have been asked, and the solution that seems popular is to set the HitTest property of the child of axes1 to 'off'. I do this when the image is created. But the callback for axes1 is still not called.
I am puzzled.
Can someone explain why.

Accepted Answer

Image Analyst
Image Analyst on 20 Sep 2014
It's because the image is "covering up" the axes. So when you click, you're clicking on the image, not the axes object which is underneath. I know, I know. It's quirky, but that's the way they do it. One workaround is to get the axes to respond by setting the hittest for the image to off. That way the click trickles down the the axes. The other work around is to setup a button down callback for the image so that it's the image's callback that actually gets called rather than the axes's callback. The drawback is that (I believe) you have to either set hittest to off or reestablish the callback whenever you display a new image array in the axes. Study this snippet
% Display in axes, storing handle of image for later quirk workaround.
hold off; % IMPORTANT NOTE: hold needs to be off in order for the "fit" feature to work correctly.
axesChildHandle = imshow(imgOriginal, 'InitialMagnification', 'fit');
% !!!! QUIRK workaround.!!!!
% Make it so that if they click in the image axes, it will execute the
% button down callback. Now it won't -- unless you do this quirk workaround.
% Double click on the dialog box's (main figure's) background to bring up the property inspector.
% Change both the WindowButtonDownFcn and ButtonDownFcn properties so that they are blank.
% Also set the main figure's HitTest to off. Then, make sure you already have the handle to the
% image living in the axes by getting it from an imshow. Then do this:
set(axesChildHandle, 'ButtonDownFcn', @axesImage_ButtonDownFcn);
% Put everything you want to do when they click the image
% into the function called axesImage_ButtonDownFcn()
% !!!! End QUIRK workaround.!!!!
  3 Comments
Image Analyst
Image Analyst on 20 Sep 2014
Well, the theory seemed right. But it looks like I actually set up a new callback for the image, so maybe I realized the hittest off approach didn't work. So use that method (set up a new callback for the image itself) like I did. I know for a fact that that works. I would usually set up the call back to display the image full screen in imtool - that's what I'd do anyway, you can do whatever you want.
John
John on 20 Sep 2014
Edited: John on 20 Sep 2014
Thank you Image Analyst.
I wonder if a MATLAB representative is willing to comment on the apparent paradox. Why is the callback for the axes not being called when the hittest for the image child of the axes is off?

Sign in to comment.

More Answers (0)

Categories

Find more on Migrate GUIDE Apps in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!