In matlab if I've a context menu with handle cxmenu_Options which is linked to different three uicontrol objects.
Inside the context menu callback function:
Code Demo:
function demoOnContextMenus
hFigure = figure;
hControl = uicontrol( ...
'Parent' , hFigure , ...
'Style' , 'Edit' , ...
'Position' , [200 200 180 40] , ...
'Tag' , 'IamControl' , ...
'String' , 'UI-Control');
hCxMenu = uicontextmenu( ...
'Tag' , 'IamMenu' , ...
'Callback',#CxMenuCallback);
set(hControl,'UIContextMenu',hCxMenu);
function CxMenuCallback(objectHandle,eventData)
tag = get(gcbo,'tag');
helpdlg(tag);
end
end
How Can I get the handle of the uicontrol which the context menu has been called from ?
There are two ways to access the handle:
gco returns the handle of the currently selected object. Thus tag = get(gco,'tag') will return IamControl.
Alternatively, you can pass the handle directly to the callback (in case the hierarchy becomes more complicated, since gco will only give you the top-level handle of the eventual chain):
handleToPass = hControl;
hCxMenu = uicontextmenu( ...
'Tag' , 'IamMenu' , ...
'Callback',#(oh,evt)CxMenuCallback(oh,evt,handleToPass));
set(hControl,'UIContextMenu',hCxMenu);
function CxMenuCallback(objectHandle,eventData,handleOfCaller)
tag = get(handleOfCaller,'tag');
helpdlg(tag);
end
Using Matlab's guide environment I have found another way to determine the caller.
The command gco (get current object) simply did the job.
In my case the context menu provides the option to open a path specified in an "Edit Text" object in Windows Explorer.
function open_in_browser_Callback(hObject, eventdata, handles)
cur_obj=gco;
cur_path=get(cur_obj,'String')
if(~isempty(cur_path))
winopen(cur_path);
end
With this solution I was able to use the same context menu for two "Edit Text" objects.
Related
I have created a very simple GUI in appdesigner (Matlab) with one dropdown menu. Additionally, I took the code that got generated (under 'Code View' tab) and pasted that in a normal .m file (because, I want to further add some more contents to this code). My question is how can I access certain variable from this self generated code, so that I can play with that value outside of the main class?
For example:
In App class, for this dropdown menu section, following line of code got generated:
app.ColorDropDown = uidropdown(app.UIFigure);
app.ColorDropDown.Items = {'Red', 'Blue', 'Yellow'};
app.ColorDropDown.Position = [277 178 140 22];
app.ColorDropDown.Value = 'Red';
Outside of this app class: Depending upon the value that was selected in this dropdown menu, I want to capture that in a normal variable, and show some other results based on the color selected
Thanks
It seems like the essence of your question is about sharing data between GUIs as you state you want to "show some other results based on the color selected".
Note: MATLAB documentation cautions: Do not use UserData property in apps you create with App Designer.
The documentation goes on to recommend approaches for sharing data among app designer apps and creating multiwindow apps in app designer.
For the sake of completeness, I'll provide a detailed example, different from the MATLAB documentation, of how this can be accomplished entirely within the App Designer.
Setup
I created 2 app designer apps, controlGUI.mlapp and plotGUI.mlapp. Running controlGUI() loads both mlapp files at once and then allows you to control aspects of the plotGUI from callbacks in the controlGUI. Of course, the plotGUI could do anything but I have it changing visual aspects of the plotted data.
Details
For simplicity, I am setting the controlGUI be the main application. I can do this be adding a property in controlGUI named PlotWindow and having it contain the output of calling plotGUI(); the other mlapp. I also have a callback function I recycle for the three dropdowns that updates a DATA property in the plotGUI. This DATA property has a listener attached that fires a callback to update the uiaxes object.
The plotGUI
The magic is really in this object. That is, I created a property named DATA and altered the access. By setting the property access SetObservable = true, we can then add a PostSet event listener, which I stored in a private property called dataChangedListener during the startupFcn.
properties (Access = public, SetObservable=true)
DATA % A struct with xdata, ydata, fields. Other line prop fields ok
end
properties (Access = private)
dataChangedListener % listener object for when DATA is changed.
end
Then the startup function, startupFcn, initializes the DATA property with some (arbitrary) data as struct then adds and enables the PostSet listener.
% Code that executes after component creation
function startupFcn(app, data)
if nargin < 2
% create a default dataset
data = struct();
data.xdata = linspace(0,1,1001);
data.ydata = sin(data.xdata.*2*pi*10);%10hz signal
data.color = app.Axes.ColorOrder(1,:);
end
app.DATA = data;
% plot the data
line(data, 'parent', app.Axes);
% add and enable PostSet event listener for the DATA property
app.dataChangedListener = addlistener(...
app,'DATA','PostSet', ...
#(s,e) app.updatePlot ...
);
app.dataChangedListener.Enabled = true;
end
The PostSet listener calls the method app.updatePlot(), so we have to add this method to our app. This method will get called whenever anything in app.DATA gets modified. So I created the "function" (as the Code Browser calls it) which simply deletes the axes children (the existing line) and uses the low-level version of line() to draw a primitive line based on the app.DATA struct object:
function updatePlot(app)
%clear plot
delete(app.Axes.Children);
% draw the new plot
line(app.DATA, 'parent', app.Axes);
end
Yes, line() will accept a struct which has field names that correspond to valid line properties but I can't seem to find the reference specifically. But if you read about the inputParser object... sorry, getting off topic.
The controlGUI
This object is simpler. It holds the plotGUI in a property, allowing direct access to the plotGUI properties and public methods.
properties (Access = public)
PlotWindow = plotGUI() % holds the reference to the plot window
end
I also created an updatePlot callback method here, different from the plotGUI method, bad naming on my part. Nonetheless, this control method takes the values from controlGUI dropdowns and then modifies the plotGUI DATA struct, stored in app.PlotWindow.DATA. So this one callback is called whenever any of the dropdowns are changed (ValueChangedFcn). Consequently, the PostSet listener for the DATA struct will fire the callback to update the plot accordingly.
% Value changed function: LineColor, LineStyle, MarkerStyle
function updatePlot(app, event)
mStyle= app.MarkerStyle.Value;
lStyle= app.LineStyle.Value;
lColor = app.LineColor.Value;
d = app.PlotWindow.DATA;
switch mStyle
case 'none'
d.marker = 'none';
case 'circle'
d.marker = 'o';
case 'diamond'
d.marker = 'diamond';
case 'point'
d.marker = '.';
end
switch lStyle
case 'none'
d.linestyle = 'none';
case 'solid'
d.linestyle = '-';
case 'dashed'
d.linestyle = '--';
case 'dotted'
d.linestyle = ':';
end
d.color = lColor;
% set the data back into the plotGUI
% The plotGUI's DATA PostSet listener will update the actual plot
app.PlotWindow.DATA = d;
end
You aren't supposed to copy/paste the code outside of the code editor with App Designer. If you want to add your own code, you should add a new function to your class using the "Function" button in App Designer. The app can also call any other matlab function so you could just pass the information from the app to another function by calling it inside the App Designer code
For example see this example from a demo I created. It uses a drop down ChartTypeDropDown to determine what type of chart it should draw. I added a new function called DrawChart which uses the data from the GUI to draw a graph depending on the values selected/entered in to the various boxes.
function results = DrawChart(app)
chartType = app.ChartTypeDropDown.Value;
chartTime = app.TimeEditField.Value;
chartA = app.AEditField.Value;
chartB = app.BEditField.Value;
chartC = app.CEditField.Value;
t = [0:0.1:chartTime];
if strcmp(chartType,'Sin')
y = chartA * sin(chartB*t)+chartC;
elseif strcmp(chartType,'Cos')
y = chartA * cos(chartB*t)+chartC;
elseif strcmp(chartType,'Exp')
y = exp(t);
else
y = x;
end
ax = app.UIAxes;
ax.Title.String = chartType;
plot(ax,t,y);
end
This function is called by the callback linked to a button
function DrawButtonPushed(app, event)
DrawChart(app);
end
Note how I call regular matlab functions such as sin/cos/exp. These could just as easily be a Matlab function that you have written.
I am making an app to track my finances and I am confused as how to pass a string to a callback function in a uicontrol pushbutton object.
For instance:
classdef moneyapp < handle
methods (Access = public)
function app = moneyApp
% uicontrol object example
app.NewSymbolGLMC = uicontrol(app.FigureGLMC,...
'Style','pushbutton','Position',[300 60 200 20],...
'String','New Stock',...
'Callback', {#app.newStock,'Account Name'});
end
function newStock(src,eventData,account)
% Do something with the string, 'Account Name'
end
end
end
end
I am confused as to how to get the string, 'Account Name', to the newStock function. This is an essential part to my code and I just think my syntax is not correct; more examples of the code can be provided if needed. Any help would be greatly appreciated!
Since newStock is a method of your class, the first input must be the object itself. Because of this you need four input arguments in your function definition:
the instance, the source and event data (the default inputs), and the account name.
function newStock(obj, src, eventData, account)
As a side note, the capitalization of your constructor (moneyApp) must match the capitalization of the class (moneyapp) to be treated as a constructor.
Initially I am create a figure in GUI with two button (btnStart , btnNext ) and one axes (P_axes). For above two buttons I am using callback function.
In first button callback Function
function btnStart_callback(hObject,eventdata ,handles)
load MRI;
d = D(:,:,1);
handles.Img = imshow(d,'Parent' , P_axes);
setappdata(handles.figure1 , 'Indx' , 1)
setappdata(handles.figure1 , 'Data' , D)
end
In second button callback Function
function btnNext_callback(hObject,eventdata ,handles)
indx = getappdata(handles.figure1 , 'Indx');
D= getappdata(handles.figure1 , 'Data');
d = D(:,:,indx+1);
set(handles.Img , 'CData',d);
setappdata(handles.figure1 , 'Indx' , indx+1);
end
In the second callback function i got one in the line set(handles.Img , 'CData',d);
error is "Invalid or deleted object. "
why this error is occur and how to solve it ?
As mentioned by Rattus Ex Machina that's hard to debug without seeing the rest of your code. If that could be of any help, here is a simple GUI which does what you seem to be after. Take the time to play around with it to see what might have caused the error in your code. I suspect that's a basic issue but I think it comes form elsewhere in the code than the part you have shown.
function LoadMRIGUI
clc
clear all
handles.figure1 = figure('Position',[100 100 400 400],'Units','normalized');
P_axes = axes('Units','normalized','Position',[.2 .2 .6 .6]);
handles.ButtonStart= uicontrol('Style','push','String','Start','Position',[40 350 50 30],'Callback',#(s,e) btnStart_callback);
handles.ButtonStop= uicontrol('Style','push','String','Next','Position',[100 350 50 30],'Callback',#(s,e) btnNext_callback);
%// === NEW === \\%
%// text box to see current index
handles.IdxTitle = uicontrol('Style','text','String','Index','Position',[160 350 50 20]);
handles.Idxbox = uicontrol('Style','text','String','1','Position',[220 350 50 20]);
function btnStart_callback
%// === NEW === \\%
S = load('mri');
d = S.D(:,:,1);
handles.Img = imshow(d,'Parent' , P_axes);
setappdata(handles.figure1 , 'Indx' , 1)
setappdata(handles.figure1 , 'Data' , S.D)
end
function btnNext_callback
indx = getappdata(handles.figure1 , 'Indx');
D= getappdata(handles.figure1 , 'Data');
d = D(:,:,indx+1);
set(handles.Img , 'CData',d);
setappdata(handles.figure1 , 'Indx' , indx+1);
set(handles.Idxbox,'String',num2str(indx+1));
end
end
Sample screenshot:
Hope that helps!
Without seeing the context, it's tough to be absolutely sure what you're up to. Importantly, are these functions defined in the same, or different, files? There does seem to be an obvious problem which could cause the error you are seeing:
function btnStart_callback(hObject,eventdata ,handles)
load MRI;
d = D(:,:,1);
handles.Img = imshow(d,'Parent' , P_axes);
setappdata(handles.figure1 , 'Indx' , 1)
setappdata(handles.figure1 , 'Data' , D)
end
In the above, handles is passed in, modified, and then discarded when the function ends. If the functions are defined in different files, that value you store in .Img will never be seen again, which is why your second callback is throwing an error when you try to use it.
You are using the appdata approach for sharing data between the two functions. This will certainly work, but if you are using that approach you need also to share handles.Img.
An alternative approach, that I would favour, would be to place both of these callbacks as nested functions inside the main file representing your "application" (which creates the GUI, etc.). That way, they can share data at the file scope level (variables defined in the root function are visible in nested functions) and you don't need all the calls to appdata functions.
Your application would take this form:
function myapp
% define a variable here
my_handle = [];
function callback1(h, e)
% and it is visible here
my_handle = gcf;
end
function callback2(h, e)
% and also here
set(my_handle, 'monkeys', 'maximum');
end
end
I am new of Matlab GUI and i have the following problem.
I have declared a slider control and his properties, and i have added a listerner to the callback and to the PostSet event handler (i think that it is tecnically called event handler) as you can see below:
function [] = HandlerSlide()
%HANDLERSLIDE Summary of this function goes here
% Detailed explanation goes here
clf;
due = '2';
hSlider = uicontrol( ...
'Style','slider', ...
'Callback',#(s,e) disp(['hello ',num2str(due),' asdad']),...
'Position', [400 30 200 20] ... %[x,y, widht, height]
);
hListener = addlistener(hSlider,'Value','PostSet',#pippo);
end
function [] = pippo(s,e)
disp('ciao');
end
As you can see i have used parameter "due" in the Callback handler (the anonymous function). Now i would like to pass parameter to use in the "pippo" function without declare it as anonymous function. Is it possible?
In other words i would like to declare "hListerner" like this:
hListener = addlistener(hSlider,'Value','PostSet',#pippo{parameter1,parameter2, etc ...});
function[] = pippo(s,e, parameter1, parameter2, etc ...)
Beside how can i use in the main the value returned by "pippo"?
thank you in advance :D
Inputs in handle functions are added like that:
hListener = addlistener(hSlider,'Value','PostSet',{#pippo,parameter1,parameter2});
You have to be careful then in the function, as "parameter1" won't be the first input but the third (after source and eventdata).
I created a matlab GUI using GUIDE.
I created several panels with static text boxes inside them. I would like to write values to all the boxes once I push an "update" pushbutton.
for instance, I would like to write to a box with tag AV1, and the text box is inside panel "uipanel2".
Both ways give errors:
set(handles.AV1,'String','hi');
The above code does not work as it says the field does not exist. This makes sense as I need to access the panel first.
So below I access the panel, but how do I get to its children?
set(handles.uipanel2.AV1,'String','hi');
this code gives the following error: Attempt to reference field of non-structure array.
Children is a field so if you want the children you can try get(handles.uipanel2,'Children') and it will give you an array with handles to the children. It will look like numbers to you in the same way that the handle to uipanel2 looks like a number.
Here's an example:
function testGUI
fig = figure(1);
panel = uipanel(fig);
tbox = uicontrol('Style','text','String','hello','parent',panel);
ch = get(panel,'Children')
get(ch,'Type')
get(ch,'String')
end
It shows how to get the Children of the panel object with ch = get(panel,'Children') which should print something to console that looks like:
ch =
182.0011
And to show you that this ch is in fact a handle to the static textbox that is a child of the panel, I've printed out the type and string of ch to console which should be the following:
ans =
uicontrol
ans =
hello
And here's an example of how to get the string in a textbox to update when you press a Push Button:
function testGUI
fig = figure(1);
panel = uipanel(fig);
tbox = uicontrol('Style','text','String','hello','parent',panel);
button = uicontrol('Style','PushButton','String','push me',...
'Position',[100 100 50 25]);
set(button,'Callback',#mycallback)
function mycallback(src,eventdata)
set(tbox,'String','updated')
end
end