How can I access data from outside the app class in appdesigner (Matlab)

荒凉一梦 提交于 2020-12-02 02:00:30

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!