I realize that App designer does not support interactive figure manipulation, but I am wondering if I can open a separate figure window (not a UI window) with my graphic displayed on it so that I can still get the location of my mouse clicks. Currently the code below displays the figure on my GUI, and then opens another blank figure that records my mouse clicks. This is fine, but I need to also display the figure in the new window as well, and am having trouble doing so.
first frame = vid(:,:,:,1);
imshow(firstframe,'Parent',app.UIAxes);
[centers_X centers_Y]=getpts;
What worked for me was setting a callback on the image rather than the axes:
ih = imshow(firstframe,'Parent',app.UIAxes);
ih.ButtonDownFcn = {#im_ButtonDownFcn, app}; %app will be passed to the callback
Then in a separate file in the same folder (or as a private function within the appdesigner... it should work but I haven't tried it):
function im_ButtonDownFcn(im, hit, app)
mouse_pos = flip(hit.IntersectionPoint(1:2)); %gives floats. Round if you want integers e.g. for indexing pixels
Related
I created a uitable (new version using appdesigner) in MATLAB and wanted to support right clicking on cells and showing a cell specific context menu. Much to my surprise there seemed to be no way to support this.
The context menu only seems to trigger with right click on the uitable, but there is no way of knowing which cell was selected (I think, maybe not?). I created a workaround where I left clicked to select a cell, and during that selection I right clicked using a Java Mouse robot to trigger the context menu. This is super ugly but sort of works. Except, if you need to bring up the menu twice on the same cell. Apparently the cell selected callback only fires once for the cell, until a new cell is selected. I tried literally putting two tables in the same spot and upon selecting one toggling to the other, but the memory of cell selection is table specific, so this only worked for two clicks before both tables had been clicked on the same cell, and toggling visibility back to the first resulted in the cell selection callback not firing (since the cell had not changed) . I tried various approaches to try and deselect the cell (disable/enable, visibility change, data change, etc.), but the cell selection callback never changed.
I even tried having duplicate columns, where the goal was to hide a column, where normally columns 1 and 2 would be visible (column 3 out of view due to size), and then on clicking on column 2, column 2 would hide itself (0 width) and column 3 (an exact duplicate) would move into its place, thus seeming to the user like multi-clicking was supported. Unfortunately I can't set the column width to 0 -- or rather, setting it to 0 doesn't completely hide the column. Instead there seems to be some minimal width to the column and the whole thing looked awful.
I wanted to do something similar with a listbox (right click support), but again I couldn't figure out how to identify where I was right clicking. I eventually settled on left clicking on a listbox and using the mouse robot approach to right click to bring up the context menu. Unlike the uitable, it was fairly easy to clear the selection on the listbox (set listbox.Value = {}). However, I strongly dislike the left click instead of right click approach and I'd rather have multiple columns.
Any suggestions would be much appreciated!!!
So I found an approach that is better than using a robot. I had tried this but was missing a critical portion which I will describe below.
Upon selecting a row in the table, the open command can be used to launch a context menu. My problem was that I didn't know where to launch the menu. I tried CurrentPoint for the figure, but it was 0,0 (or in general not valid)
Here's the current documentation for CurrentPoint:
Current point, returned as a two-element vector. The vector contains
the (x, y) coordinates of the mouse pointer, measured from the
lower-left corner of the figure. The values are in units specified by
the Units property.
The coordinates update when you do any of the following:
Press the mouse button within the figure.
Release the mouse button after pressing it within the figure.
Press the mouse button within the figure, and then release it outside
the figure.
Rotate the scroll wheel within the figure.
Move the mouse within the figure (without pressing any buttons),
provided that the WindowButtonMotionFcn property is not empty.
If the figure has a callback that responds to mouse interactions, and
you trigger that callback faster than the system can execute the code,
the coordinates might not reflect the actual location of the pointer.
Instead, they are the location when the callback began execution.
If you use the CurrentPoint property to plot points, the coordinate
values might contain rounding error.
Here's the critical line again:
"Move the mouse within the figure (without pressing any buttons), provided that the WindowButtonMotionFcn property is not empty."
So when a selection of a cell happens, the CurrentPoint is not valid. However, if we simply define a WindowButtonMotionFcn, then it is!
So the general idea is to have a callback for the table when a cell is selected (SelectionChangedFcn) and to set a dummy callback for WindowButtonMotionFcn
The final point is that a context menu can be launched with the open function if you specify a given location to launch it at. This is different from attaching it to an object and having it automatically launch on right click.
Here's some example code. If you comment out the callback for windows motion then the whole thing doesn't work! Unfortunately it is a left click for targeting the cell but at least it avoids the non-sense I was using with a java robot right click.
classdef wtf < handle
properties
h %struct, this was an appdesigner handle
cm %context menu
end
methods
function obj = wtf()
h = struct;
h.UIFigure = uifigure();
h.UITable = uitable(h.UIFigure);
obj.h = h;
obj.h.UITable.CellSelectionCallback = #obj.tableCall;
%obj.h.UITable.SelectionChangedFcn = #obj.tableCall;
%Some data ...
s = struct;
s.a = (1:4)';
s.b = (5:8)';
obj.h.UITable.Data = struct2table(s);
%Our context menu
cm = uicontextmenu(obj.h.UIFigure);
m = uimenu(cm,'Text','Menu1');
obj.cm = cm;
%WTF ... without this we don't get a valid CurrentPoint
obj.h.UIFigure.WindowButtonMotionFcn = #obj.mouseMove;
end
function tableCall(obj,x,y)
%y - event info
%x - impacted object
cp = get (obj.h.UIFigure, 'CurrentPoint');
open(obj.cm,cp(1),cp(2));
selected_cell = y.Indices;
%selected_cell = y.Selection;
x.Selection = []; %allows reselecting same cell without
%needing to select another cell first
%Now we can run something on the context menu
%that targets the selected cell
end
function mouseMove(obj,x,y)
%we could store a point here
end
end
end
I have made a Gui program that I compile to EXE application which lots csv file into graph data. I buit a save button but I do not know how save figure with different name each time cause (savefig anduisave both uses matlab program). I am posting my code below if anyoff you guys figure out how to save gui figue into image or anything that does require matlab to open. Last function is the callback function for save button.
function ma_Callback(hObject, eventdata, handles)
% i tried uisave but not possible to run computer without matlab cause mcr
% does not run uisave
% i tried copyopbj but since i did not put a name on my figure it did not
% work
%savefig
If you are trying to save a kind of image from your figure, then the best option which supports many aspects, is using print function.
I have already done this in a compiled app and it works perfect. Using print function you can set different file type(vector formats like *.svg are also supported), resolution(dpi), and so many others.
Although you can use print function directly on the figure, but I found that the best way (More Customization like removing or adding some objects and changing many options) is to follow this steps:
Create another figure with Visible='on' but a position that is out of screen with the same width and height of Main Figure.
normalized position = [-1, -1, ?, ?]. (Create this figure in start up and don't destroy it until your app exits, let call it Print Figure).
Copy your figure content (or the parts you are interested in) using copyobj to that figure (you may need to set Parent property of some key objects like panels to this new figure). They would look exactly as they look in the main figure, because they have the same properties. you can add or remove some objects in this step.
Change aspect ratio of "Print Figure" for a better output.
Print this figure with all options (file format, dpi, ...) you need. in my own GUI i allowed the user to change this settings with an input dialog.
In my app i used functions like winopen to show the output, and output directory to the user, when the print task was done. Print process takes some time, specially if dpi is huge, so it is also a good idea to inactivate buttons and show wait cursor.
Update:
a simple usage would be:
print(MainFigure, 'myFileName', '-dpng', '-r300')
In one GUI (viewer) I have an image that shows a 2D slice through a 3D image cube. A toolbar button opens a second GUI (z-profile) that plots a 2D graph showing the z-profile of one pixel in the image cube. What I want is to be able to update this plot dynamically when a different pixel is clicked in the original viewer GUI. I've looked in to linkdata but I'm not sure if that can be used to link across two GUIs. Is there a simple way to do this without re-creating the second GUI each time a new pixel is clicked and feeding in the new input location?
You can definitely doing it without recreating the second GUI every time.
Without knowing your specific code I would say that you should store a reference to the second GUI in the first GUI, then in a callback for clicking a pixel in the first GUI, change data in the second GUI via the stored reference (e.g. figure handle). You can store arbitrary data in a figure, for example by using function guidata. A bit of code.
...
figure2 = figure();
figure1 = figure('WindowButtonDownFcn',#myCallback);
guidata(figure1, figure2);
...
function myCallback(obj,eventdata)
figure2 = guidata(obj);
...
Even easier but a bit more error-prone would be to use global variables for storing the references.
I'm working on creating a GUI in matlab using GUIDE. However, i'm not exactly sure how to do the following, and was looking for some tips/advice.
Problem
I want to open a directory and display all the images in that directory in the GUI interface when if it's selected. However, since I will never know exactly how many images there are I am not entirely sure how to do this in the GUI.
Essentially, I want to open the directory and all the images to be displayed in a grid on the GUI similar to that in iphoto.
Current code
Currently, I can open a directory fine, and get all the required information as follows:
directory = uigetdir(pwd, 'Directory Selector');
files = dir(fullfile(directory, '*.jpg'));
strcat(strcat(directory, '/') , files.name) %outputs each file's location
I'm just not sure how to translate this information into the GUI without writing numerous handles.axes1. I understand that since I know this info I could loop over them, but would I not have to create the axes to begin with?
You probably don't want to do this with individual controls - the reason is that MATLAB will have to render each and every one, which will be slow if the directory has a lot of images. Clearly, you can only display a certain number of images on screen at once. You would also have to write your own scrolling code (or some kind of pagination control).
If you have MATLAB > R2008, you can put images in uitable cells using HTML:
% Example for a control with a 'String' property
set(handles.myControl, 'String', '<html><b>Logo</b>: <img src="http://UndocumentedMatlab.com/images/logo_68x60.png"/></html>');
See also this post and this Undocumented MATLAB page.
A different option would be to use the Windows common controls ListView.
A simpler way of doing this would be to have a single image and a listbox of files; an example is here
You can add components to a GUI pprogrammatically. There's more information here.
Each new axes can be added with something like this:
ah = axes('Parent',hObject,'Position',[left bottom width height]);
where left, bottom, width and height define the size and position of the axes. You'll need to change the position for each axes you create and keep track of the axes handles.
I have some code that generates a number of MATLAB figures. At the end of my program I want to publish these figures in a report. I have a script, which is passed to publish(), that uses openfig() to include the figures in the document.
This causes these figures to flash up on the screen. This is particularly annoying when I am opening figures inside a loop using a combination of close and snapnow. I've tried making these figures invisible using
openfig(PathToFigure, 'new', 'invisible')
This stops the image appearing on the screen but also stops it appearing in the report.
Is there a way of including .fig files in the report without having them appear on screen?
Open the figure with f=openfig(PathToFigure, 'new', 'invisible'). Then move the figure off-screen by setting its Position property (perhaps to something with negative values for the left and bottom pixels), set its Visible property to on, call snapnow. Delete the figure.
I would actually recommend setting their visibility to 'off' when you create those figures with
f = figure('Visible','off');