问题
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
回答1:
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
回答2:
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.
来源:https://stackoverflow.com/questions/51771263/how-can-i-access-data-from-outside-the-app-class-in-appdesigner-matlab