I know this question has been asked before, but I can't find any good answers. I keep stumbling upon WindowButtonMotionFcn, but I don't really understand how to use it. In my program I want to be able to click and store coordinates ONLY when the user is above a certain axes, so that the normal mouse appears for the rest of the GUI and they can play with other buttons. Thanks for any insight.
I would recommend not using WindowButtonMotionFcn and instead use the ButtonDownFcn of your axes object. This way MATLAB takes care of your hit detection for you.
For example:
function testcode()
h.myfig = figure;
h.myaxes = axes( ...
'Parent', h.myfig, ...
'Units', 'Normalized', ...
'Position', [0.5 0.1 0.4 0.8], ...
'ButtonDownFcn', #myclick ...
);
end
function myclick(~, eventdata)
fprintf('X: %f Y: %f Z: %f\n', eventdata.IntersectionPoint);
% Insert data capture & storage here
end
Prints your coordinate every time you click inside the axes but does nothing when you click anywhere else.
EDIT:
Since this is a GUIDE GUI the easiest approach is to utilize getappdata to pass data around the GUI. To start, you need to modify your GUI_OpeningFcn to something like the following:
function testgui_OpeningFcn(hObject, eventdata, handles, varargin)
% Choose default command line output for testgui
handles.output = hObject;
% Initialize axes click behavior and data storage
set(handles.axes1, 'ButtonDownFcn', {#clickdisplay, handles}); % Set the axes click handling to the clickdisplay function and pass the handles
mydata.clickcoordinates = []; % Initialize data array
setappdata(handles.figure1, 'mydata', mydata); % Save data array to main figure
% Update handles structure
guidata(hObject, handles);
And then add a click handling function elsewhere in your GUI:
function clickdisplay(~, eventdata, handles)
mydata = getappdata(handles.figure1, 'mydata'); % Pull data from main figure
mydata.clickcoordinates = vertcat(mydata.clickcoordinates, eventdata.IntersectionPoint); % Add coordinates onto the end of existing array
setappdata(handles.figure1, 'mydata', mydata); % Save data back to main figure
You can then pull the array into any other callback using the same getappdata call.
Related
I am attaching a sample GUI codes, which has two axes with 2 images and when I use ginput to select seed point I am able to select on either axes, Is there anyway to limit the ginput to a specific axes
% --- Executes on button press in open.
function open_Callback(hObject, eventdata, handles)
% hObject handle to open (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global img1;
global img2;
img1 = imread('peppers.png');
img2 = imread('rice.png');
axes(handles.axes1);
imshow(img1,[]);
axes(handles.axes2);
imshow(img2,[]);
% --- Executes on button press in seedpointSelect.
function seedpointSelect_Callback(hObject, eventdata, handles)
% hObject handle to seedpointSelect (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global img1;
global img2;
global x;
global y;
axes(handles.axes1);
imshow(img1,[]);
[y,x] = ginput(handles.axes1);
y = round(y); x = round(x);
set(handles.xcord,'String',num2str(x));
set(handles.ycord,'String',num2str(y));
Any help on limiting ginput to a specific axes,
Thanks,
Gopi
In older versions of MATLAB you used to be able to change the HitTest property of the axes to ignore the click from ginput
set(handles.axes2, 'Hittest', 'off')
The better approach though is to use ButtonDownFcn as you have much more control over mouse events with an axes object.
From within your OpeningFcn
set(handles.axes1, 'ButtonDownFcn', #mouseCallback)
Then you'll need to create the callback function
function mouseCallback(src, evnt)
handles = guidata(src);
% Get the current point
xyz = get(src, 'CurrentPoint');
x = xyz(1,1);
y = xyz(1,2);
% Store x/y here or whatever you need to do
end
Don't use ginput, create a mouse click callback instead (ButtonDownFcn). You can set the callback to, for example, remove the callback function from the axis. In your main program, which sets the callback, you then waitfor that property to change. As soon as the user clicks, you get control back, and you can then read the location of the last mouse click (CurrentPoint). Note that the position you read out is in axis coordinates, not screen pixels. This is a good thing, it most likely corresponds to a pixel in the image displayed.
So I'm building a classifier of images. In the GUI a image loads and insert a value on a text box, and push a button. I'm having a problem loading the image in the axes. Because when the axes function is called the handles is zero(due to:% handles empty - handles not created until after all CreateFcns called). And my problem is, how do I get to just call one image at a time for the axes.
The ideal solution, is I create a handles.images=imagedatastore, and every time I push the button I add to a counter(which I already have made) and then that give the indices to get the image from the datastore. My problem with this is that I can't get the first picture, because in the beginning the handles are empty. I have made the callfunction for the axes:
% --- Executes during object creation, after setting all properties.
function axes1_CreateFcn(hObject, eventdata, handles)
% hObject handle to axes1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
[pict_croped,Nphotos,Date_img] =getcropedimagages;
handles.img =pict_croped;
i=readimage(handles.img,1);
% axes(hObject)
imshow(i)
% Hint: place code in OpeningFcn to populate axes1
but this has two problems, first, I don't really want to call the function that creates the datastore all the time I push the button, second, I still can't get the indice of the counter to be in the function,if I have:
i=readimage(handles.img,handles.counter)
it will give me the error in the first time, of not having handles.counter
Any idea how to solve this?This is the first GUI I'm building.
The issue is very clearly in the comment that GUIDE provides for you. The handles struct isn't populated until all CreateFcn have been run so you'll want to use the OpeningFcn to do any initialization of the graphics objects. You can then add any data you need to the handles struct and save it using guidata so that it's available from within all of your other callback functions.
function OpeningFcn(hObject, eventData, handles)
[pict_croped,Nphotos,Date_img] = getcropedimagages;
handles.img = pict_croped;
i = readimage(handles.img,1);
imshow(i, 'Parent', handles.haxes1)
% "Save" the changes to the handles object
guidata(hObject, handles)
Well, I end up with:
in the opening fucntion:
i = readimage(handles.img,handles.counter);
imshow(, 'Parent', handles.axes1)
and in the button call back:
i = readimage(handles.img,handles.counter);
imshow(i, 'Parent', handles.axes1)
inthe end is a very simple solution, I think I was just mind blocked over the first iteration...
I would like to add two vertical moving lines to the graph and depending on their position it would change the values in the boxes Start and End.
I would also like to do the other way around: by changing the values in the boxes Start and End it would move the vertical lines to the assigned positions.
I have this inside the pushbutton1_Callback
hold on;
plot(x,y);
SP = 20;
line([SP,SP],get(handles.axes1,'Xlim'),'Color','red');
I suppose I would have to create callback events for mouseButtonDown and mouseButtonUp, but I am very new to Matlab and don't know what to put in those callbacks
The way around:
by typing values in edit boxes Start and End you can plot verticle lines. In each of these edit boxes (my case edit1 and edit2) callbacks write
EDIT: now old lines are deleted
function edit1_Callback(hObject, eventdata, handles)
start=str2num(get(hObject, 'string'));
if isfield(handles,'startLine'); delete(handles.startLine); end
handles.startLine=line([start,start],ylim,'Color',[.8 .8 .8]);
guidata(hObject, handles);
function edit2_Callback(hObject, eventdata, handles)
LineEnd=str2num(get(hObject, 'string'));
if isfield(handles,'LineEnd'); delete(handles.LineEnd); end
handles.LineEnd=line([LineEnd,LineEnd],ylim,'Color',[.8 .8 .8]);
guidata(hObject, handles);
I am working on MATLAB GUI in which i am updating the work-space variables in a list box and then trying to plot them on axes in GUI.
I have one other push button for performing plotting operation. But when i click on plot button, i get plots in a figure which pops up.
But according to my application i have to create the plots in axes. I am unable to do so
Kindly help
MY plot button code is as follows:
function plot_button_Callback(hObject, eventdata, handles, varargin)
% hObject handle to plot_button (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
[x] = get_var_names(handles);
if isempty(x)
return
end
if isequal(x,'a')
% figure(gcf)
try
figure(1)
evalin('base',['plot(a,b,''--r'')'])
hold all
evalin('base',['plot(a,c,''k'')'])
hold all
evalin('base',['plot(a,d,''g'')'])
figure(2)
evalin('base',['plot(a,e,''g'')'])
hold all
grid on
catch ex
errordlg(...
ex.getReport('basic'),'Error generating linear plot','modal')
end
Within each GUI callback, you have a variable called handles which is the key to editing/accessing any item in your GUI. In the case of plotting to an existing axis, you need to add an additional argument to the plot function. Here's a line of code I yanked from a GUI that I wrote:
plot(handles.axes1, xdata, ydata);
Now, this approach might not work easily for you because you are using the evalin function (which I don't recommend doing, it'd be much better to pass that information in to the gui). Regardless, a good way to implement your goal with these constraints is
a = evalin('base','a');
b = evalin('base','b');
plot(handles.axes1,a,b,'--r');
Your GUI axes might not be named axes, you'll have to check on that. You should also probably remove the figure(1) call, if I understand your goal correctly.
Also, you don't need to invoke hold all after each time you plot, once is sufficient.
I am using Matlab's GUIDE for the first time, I am trying to edit one of the two push button functions (both open an image), but editing one changes all of them. Here is a bit of code:
% --- Executes on button press in Floating.
function Floating_Callback(hObject, eventdata, handles)
clc;
axes(handles.axes1);
[Float, PathName, FilterIndex] = uigetfile('*.bmp');
if(Float ~= 0)
Floating = fullfile(PathName, Float);
FloatArray = imread(Floating);
imshow(FloatArray);
axis on;
end
% Update handles structure
guidata(hObject, handles);
% hObject handle to Floating (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% --- Executes on button press in Reference.
function Reference_Callback(hObject, eventdata, handles)
clc;
axes(handles.axes2);
[Ref, PathName, FilterIndex] = uigetfile('*.bmp');
if(Ref ~= 0)
Reference = fullfile(PathName, Ref);
ReferenceArray = imread(Reference);
image(ReferenceArray);
end
% Update handles structure
guidata(hObject, handles);
For example,
image(ReferenceArray)
will open an image in RBG, but
imshow(FloatArray)
will open in grayscale (I also do not understand why that is). But my main concern is after opening up
imshow(FloatArray)
the other image will automatically turn grayscale. I am very confused... Also, as far as I know the images ARE already grayscale, at least they are when I open them in MS paint or ImageJ.
It would be better to explicitly specify the parent handle whenever you are doing GUI stuff. For example:
imshow(img, 'Parent',handles.ax1)
and
axis(handles.ax1, 'on')
As for images and colormaps, you should understand the type of images MATLAB supports (indexed vs. truecolor). Also note that a figure has only one colormap applied to all images, although there are techniques to overcome this.