Share Data between Multi-window MATLAB Apps

Jul. 31, 2022

Introduction

Share Data in Multiwindow Apps

This example shows how to pass data from one app to another. This multiwindow app consists of (1) a main app that calls (2) a dialog box app with input arguments. The dialog box displays a set of options for modifying aspects of the main app. When the user closes it, the dialog box sends their selections back to the main app.

This example demonstrates the following app building tasks:

  • Calling an app with input arguments

  • Calling an app with a return argument that is the app object

  • Passing values to an app by calling a public function in the app

  • Writing CloseRequestFcn callbacks to perform maintenance tasks when each app closes

Copyright 2018 The MathWorks, Inc.

该示例来自MATLAB官方网站。一共有两个app,分别是 MainAppExample.mlapp 和 DialogAppExample.mlapp。在下文中,两个.mlapp代码分别在两个一级标题下完整给出,每个一级标题中的二级标题分别代表的一部分属性或方法的实现,其中带  的二级标题是最具有差异和值得重点关注的部分。


(I) MainAppExample.mlapp

image-20220731172154853

定义继承自 matlab.apps.AppBase 的子类 MainAppExample:

1
2
3
classdef MainAppExample < matlab.apps.AppBase
	...
end

MainAppExample 类主要以下几部分属性和方法:

(1)共有属性:组件

1
2
3
4
5
6
    % Properties that correspond to app components
    properties (Access = public)
        UIFigure       matlab.ui.Figure
        OptionsButton  matlab.ui.control.Button
        UIAxes         matlab.ui.control.UIAxes
    end

(2) 私有属性:DialogApp, 设置初始值

1
2
3
4
5
    properties (Access = private)
        DialogApp                   % Dialog box app
        CurrentSize = 35;           % Surface sample size
        CurrentColormap = 'Parula'; % Colormap
    end

(3)公有方法:updateplot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    methods (Access = public)
        function updateplot(app, sz, c)
            % Store inputs as properties
            app.CurrentSize = sz;
            app.CurrentColormap = c;
            
            % Update plot 
            Z = peaks(sz);
            surf(app.UIAxes,Z);
            colormap(app.UIAxes,c);
            
            % Re-enable the Plot Options button
            app.OptionsButton.Enable = 'on';
        end
    end

(4)私有方法:startupFcn, OptionButtonPushed, MainAppCloseRequest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    % Callbacks that handle component events
    methods (Access = private)

        % Code that executes after component creation
        function startupFcn(app)
            % Call updateplot to display an initial plot
            updateplot(app, app.CurrentSize, app.CurrentColormap)
        end

        % Button pushed function: OptionsButton
        function OptionsButtonPushed(app, event)
            % Disable Plot Options button while dialog is open
            app.OptionsButton.Enable = 'off';
            
            % Open the options dialog and pass inputs
            app.DialogApp = DialogAppExample(app, app.CurrentSize, app.CurrentColormap);
        end

        % Close request function: UIFigure
        function MainAppCloseRequest(app, event)
            % Delete both apps
            delete(app.DialogApp)
            delete(app)
        end

startupFcn

在启动 MainAppExample 时,App 会首先调用 startupFcn(app) 函数,根据 app.CurrentSizeapp.CurrentColormap 的初始化值,调用 updateplot(app, sz, c) 函数绘制图像。

OptionsButtonPushed

当点击 Options 按钮时,软件会执行 OptionsButtonPushed 回调函数,首先禁用掉 Options 按钮,之后弹出 DialogAppExample App

1
app.DialogApp = DialogAppExample(app, app.CurrentSize, app.CurrentColormap);

其中,DialogAppExample 是所调用对话框 App 的类名,也是.mlapp的文件名;

app.DialogApp, ` app.CurrentSizeapp.CurrentColormap` 均在(2)私有属性中有所声明。

MainAppCloseRequest

MainAppCloseRequest 函数定义了关掉主 app 时的行为:当关掉主程序时,同时删除对话框程序。

(5)私有方法:UIFigure 和 components 的初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    % Component initialization
    methods (Access = private)

        % Create UIFigure and components
        function createComponents(app)

            % Create UIFigure and hide until all components are created
            app.UIFigure = uifigure('Visible', 'off');
            app.UIFigure.Position = [100 100 449 370];
            app.UIFigure.Name = 'Display Plot';
            app.UIFigure.CloseRequestFcn = createCallbackFcn(app, @MainAppCloseRequest, true);

            % Create UIAxes
            app.UIAxes = uiaxes(app.UIFigure);
            app.UIAxes.XTickLabelRotation = 0;
            app.UIAxes.YTickLabelRotation = 0;
            app.UIAxes.ZTickLabelRotation = 0;
            app.UIAxes.Position = [56 64 341 267];

            % Create OptionsButton
            app.OptionsButton = uibutton(app.UIFigure, 'push');
            app.OptionsButton.ButtonPushedFcn = createCallbackFcn(app, @OptionsButtonPushed, true);
            app.OptionsButton.Position = [176 20 100 22];
            app.OptionsButton.Text = 'Options';

            % Show the figure after all components are created
            app.UIFigure.Visible = 'on';
        end
    end

(6)公有方法:构建 app、删除 app

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    % App creation and deletion
    methods (Access = public)

        % Construct app
        function app = MainAppExample

            % Create UIFigure and components
            createComponents(app)

            % Register the app with App Designer
            registerApp(app, app.UIFigure)

            % Execute the startup function
            runStartupFcn(app, @startupFcn)

            if nargout == 0
                clear app
            end
        end

        % Code that executes before app deletion
        function delete(app)

            % Delete UIFigure when app is deleted
            delete(app.UIFigure)
        end
    end


(II) DialogAppExample.mlapp

image-20220731172122056

定义继承自 matlab.apps.AppBase 的子类 DialogAppExample:

1
2
3
classdef DialogAppExample < matlab.apps.AppBase
...
end

(1)共有属性:组件

1
2
3
4
5
6
7
8
    properties (Access = public)
        UIFigure                  matlab.ui.Figure
        Button                    matlab.ui.control.Button
        DropDown                  matlab.ui.control.DropDown
        ColormapDropDownLabel     matlab.ui.control.Label
        EditField                 matlab.ui.control.NumericEditField
        SampleSizeEditFieldLabel  matlab.ui.control.Label
    end

(2)私有属性:CallingApp

1
2
3
    properties (Access = private) 
        CallingApp   % Main app object
    end

(3)私有方法:StartupFcn, ButtonPushed, DialogAppCloseRequest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    % Callbacks that handle component events
    methods (Access = private)

        % Code that executes after component creation
        function StartupFcn(app, mainapp, sz, c)
            % Store main app in property for CloseRequestFcn to use
            app.CallingApp = mainapp;
            
            % Update UI with input values
            app.EditField.Value = sz;
            app.DropDown.Value = c;
        end

        % Button pushed function: Button
        function ButtonPushed(app, event)
            % Call main app's public function
            updateplot(app.CallingApp, app.EditField.Value, app.DropDown.Value);
            
            % Delete the dialog box
            delete(app)
        end

        % Close request function: UIFigure
        function DialogAppCloseRequest(app, event)
            % Enable the Plot Opions button in main app
            app.CallingApp.OptionsButton.Enable = 'on';
            
            % Delete the dialog box 
            delete(app)   
        end
    end

StartupFcn

当主 app 使用代码

1
  app.DialogApp = DialogAppExample(app, app.CurrentSize, app.CurrentColormap);

调用对话框 app 时,程序首先会调用 DialogAppExample 的 StartupFcn() 函数。

因此,将主 app 调用代码和 DialogAppExample 的 StartupFcn() 函数放在一起,有助于理解调用与函数参数之间的对应关系

1
2
3
4
5
  % Call
  app.DialogApp = DialogAppExample(app, app.CurrentSize, app.CurrentColormap);
  
  % Function
  StartupFcn(app, mainapp, sz, c)

当调用对话框 app 时,主程序首先会将 app.CurrentSizeapp.CurrentColormap 属性分别传递给对话框 app 的可编辑文本和下拉菜单的值:

1
2
3
  % Update UI with input values
  app.EditField.Value = sz;
  app.DropDown.Value = c;

ButtonPushed

回调函数 ButtonPushed() 是 DialogAppExample 中 OK 按钮的回调函数。当点击 OK 按钮时,回调函数 ButtonPushed() 会调用主 app 的 updateplot(app, sz, c)公用方法⭐,更新主 app 中的图像,并删除对话框程序。

DialogAppCloseRequest

DialogAppCloseRequest 函数定义了关掉对话框 app 时的行为:当关掉对话框 app 时,恢复主 app 的 Options 按钮,删除对话框 app。

(4)私有方法:UIFigure 和 components 的初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    % Component initialization
    methods (Access = private)

        % Create UIFigure and components
        function createComponents(app)
            % Create UIFigure and hide until all components are created
            app.UIFigure = uifigure('Visible', 'off');
            app.UIFigure.Position = [600 100 392 248];
            app.UIFigure.Name = 'Options';
            app.UIFigure.CloseRequestFcn = createCallbackFcn(app, @DialogAppCloseRequest, true);

            % Create SampleSizeEditFieldLabel
            app.SampleSizeEditFieldLabel = uilabel(app.UIFigure);
            app.SampleSizeEditFieldLabel.HorizontalAlignment = 'right';
            app.SampleSizeEditFieldLabel.VerticalAlignment = 'top';
            app.SampleSizeEditFieldLabel.Position = [102 160 74 15];
            app.SampleSizeEditFieldLabel.Text = 'Sample Size';

            % Create EditField
            app.EditField = uieditfield(app.UIFigure, 'numeric');
            app.EditField.Limits = [2 1000];
            app.EditField.Position = [191 156 100 22];
            app.EditField.Value = 35;

            % Create ColormapDropDownLabel
            app.ColormapDropDownLabel = uilabel(app.UIFigure);
            app.ColormapDropDownLabel.HorizontalAlignment = 'right';
            app.ColormapDropDownLabel.VerticalAlignment = 'top';
            app.ColormapDropDownLabel.Position = [117 106 59 15];
            app.ColormapDropDownLabel.Text = 'Colormap';

            % Create DropDown
            app.DropDown = uidropdown(app.UIFigure);
            app.DropDown.Items = {'Parula', 'Jet', 'Winter', 'Cool'};
            app.DropDown.Position = [191 102 100 22];
            app.DropDown.Value = 'Parula';

            % Create Button
            app.Button = uibutton(app.UIFigure, 'push');
            app.Button.ButtonPushedFcn = createCallbackFcn(app, @ButtonPushed, true);
            app.Button.Position = [116 43 174 22];
            app.Button.Text = 'OK';

            % Show the figure after all components are created
            app.UIFigure.Visible = 'on';
        end
    end

(5)共有方法:构建 app、删除 app

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
% App creation and deletion
    methods (Access = public)

        % Construct app
        function app = DialogAppExample(varargin)

            % Create UIFigure and components
            createComponents(app)

            % Register the app with App Designer
            registerApp(app, app.UIFigure)

            % Execute the startup function
            runStartupFcn(app, @(app)StartupFcn(app, varargin{:}))

            if nargout == 0
                clear app
            end
        end

        % Code that executes before app deletion
        function delete(app)

            % Delete UIFigure when app is deleted
            delete(app.UIFigure)
        end
    end


private function vs. public function

在上述过程中,我们可以看到对话框 app 调用了主 app 的 updateplot() 方法,这是可行的,因为主 app 中所定义的 updateplot() 方法是一个 public function

image-20220731222002303

public function 主要用于多窗口的 app ,以减少代码的冗余,具体的信息可以查看文档: Reuse Code Using Helper Functions


Conclusion

制作这种多窗口的 app,重点就在于做好三个方面的代码实现 $^{[2]}$ :

  • 主 app 传递参数给对话框 app:写好主 app 的调用函数,以及对话框 app 的 StartupFcn() 函数
  • 对话框 app 返回信息给主 app
  • 定义主 app 和对话框 app 关闭时的行为

注意 $^{[2]}$ :

If you plan to deploy your app as a web app (requires MATLAB® Compiler™), creating multiple app windows is not supported. Instead, consider creating a single-window app with multiple tabs. For more information, see Web App Limitations and Unsupported Functionality (MATLAB Compiler).


References

[1] Share Data in Multiwindow Apps - MATLAB Documentation.

[2] Create Multiwindow Apps in App Designer - MATLAB Documentation.

[3] Startup Tasks and Input Arguments in App Designer - MATLAB Documentation.