可以在 App 中为 UI 组件编写回调函数,以指定用户与其交互时的行为方式。
在具有多个相互依赖的 UI 组件的 App 中,回调函数通常必须访问主 App 函数中定义的数据,或与其他回调函数共享数据。例如,如果创建一个具有列表框的 App,可能希望您的 App 根据 App 用户选择的列表框选项更新图像。由于每个回调函数都有自己的作用域,必须显式与 App 中需要访问它的那些部分共享关于列表框选项和图像的信息。为此,请使用主 App 函数以一种可以与回调共享的方式存储信息。然后,从回调函数中访问或修改信息。
存储 App 数据
App 中的 UI 组件在其属性中包含了有用的信息。例如,可以通过查询滑块的 Value 属性来查找滑块的当前位置。创建 UI 组件时,请将该组件存储为变量,以便您可以在整个 App 代码中设置和访问其属性。
除了预定义的属性之外,所有组件都有 UserData 属性,可以使用它来存储任何 MATLAB® 数据。UserData 一次只能保留一个变量,但可以将多个值存储为一个结构体数组或元胞数组。可以使用 UserData 来存储 App 中 UI 组件的句柄,以及可能需要从 App 代码中更新的其他 App 数据。一种有用的方法是将所有 App 数据存储在主 App 图窗窗口的 UserData 属性中。如果可以访问 App 中的任何组件,则可以使用 ancestor 函数访问主图窗窗口。因此,这会将所有 App 数据保存在可以从每个组件回调中访问的位置。
例如,以下代码将创建一个包含日期选择器组件的图窗。它将日期选择器和今天的日期作为一个结构体数组存储在图窗的 UserData 属性中。
fig = uifigure;
d = uidatepicker(fig);
date = datetime("today");
fig.UserData = struct("Datepicker",d,"Today",date);
注意
请仅使用 UserData 属性存储与App 用户界面直接相关的数据。如果App 使用大型数据集,或使用的数据不是在App 代码中创建或修改的,请将这些数据存储在单独的文件中,并从 App 中访问该文件。
在简单的应用程序中,可以将数据作为变量存储在主 App 函数中,然后使用输入参数或嵌套函数为每个回调提供相关数据,而不是将 App 数据存储在 UserData 属性中。
从回调函数访问 App 数据
要在组件回调函数中访问 App 数据,请使用以下方法之一:
-
访问 UserData 中的数据-使用此方法从回调函数中更新 App 数据。它要求将 App 数据存储在 UserData 属性中,如前一节中所述。
-
将输入数据传递给回调-在简单的 App 中使用此方法来限制回调可以访问的数据,并且可以更轻松地重用回调代码。
-
创建嵌套回调函数-在简单的 App 中使用此方法,让回调函数可以访问所有 App 数据,并在单个文件中组织您的 App 代码。
以下各节分别介绍了这些方法,并提供了使用相应方法在 App 中共享数据的示例。对于每个示例,最终的 App 行为都相同,即:App 用户可以在文本区域输入文本,并点击按钮从文本生成文字云。为了实现这一点,App 必须在文本区域、按钮和存放文字云的面板之间共享数据。每个示例都以不同方式共享这些数据。
如图所示:
访问 UserData
中的数据
要将所有 App 数据组织在一个位置,请将数据存储在每个组件都可以轻松访问的位置。首先,在 App 代码的设置部分,使用图窗窗口的 UserData 属性来存储组件需要从其回调中访问的任何数据。由于每个 UI 组件均为主图窗的子级,可以使用 ancestor 函数从回调中访问该图窗。例如,如果图窗包含具有按钮的面板,而该按钮存储在名为 btn 的变量中,则可以使用以下代码访问该图窗。
fig = ancestor(btn,"figure","toplevel");
然后,一旦可以从回调中访问图窗,就可以访问和修改存储在图窗的 UserData 中的 App 数据。
示例:使用 UserData
的文字云
在文字云应用中,要在 App 用户点击按钮时共享 App 数据,请将数据存储在图窗中的 UserData 属性中。定义名为 createWordCloud 的 ButtonPushedFcn 回调函数,以根据文本区域中的文本绘制文字云。createWordCloud 函数需要在点击按钮时访问文本框的值。它还需要访问面板容器以在其中绘制数据。要提供这种访问,请将图窗的 UserData 设置为存储文本区域组件和面板容器的 struct。
fig.UserData = struct("TextArea",txt,"Panel",pnl);
在 createWordCloud 函数中,访问图窗中的 UserData 属性。由于 MATLAB 会自动将执行回调的组件作为 src 传递给回调函数,可以使用 ancestor 函数从回调函数访问该图窗。
fig = ancestor(src,"figure","toplevel");
然后,可以使用该图窗来访问面板和文本。
data = fig.UserData;
txt = data.TextArea;
pnl = data.Panel;
val = txt.Value;
要运行此示例,请将 shareUserData 函数保存到 MATLAB 路径中名为 shareUserData.m 的文件中。
function shareUserData
% Create figure and grid layout
fig = uifigure;
gl = uigridlayout(fig,[2,2]);
gl.RowHeight = {'1x',30};
gl.ColumnWidth = {'1x','2x'};
% Create and lay out text area
txt = uitextarea(gl);
txt.Layout.Row = 1;
txt.Layout.Column = 1;
% Create and lay out button
btn = uibutton(gl);
btn.Layout.Row = 2;
btn.Layout.Column = 1;
btn.Text = "Create Word Cloud";
% Create and lay out panel
pnl = uipanel(gl);
pnl.Layout.Row = [1 2];
pnl.Layout.Column = 2;
% Store data in figure
fig.UserData = struct("TextArea",txt,"Panel",pnl);
% Assign button callback function
btn.ButtonPushedFcn = @createWordCloud;
end
% Process and plot text
function createWordCloud(src,event)
fig = ancestor(src,"figure","toplevel");
data = fig.UserData;
txt = data.TextArea;
pnl = data.Panel;
val = txt.Value;
words = {};
for k = 1:length(val)
text = strsplit(val{k});
words = [words text];
end
c = categorical(words);
wordcloud(pnl,c);
end
将输入数据传递给回调
当回调函数需要访问数据时,可以将该数据作为输入直接传递给回调函数。除了 MATLAB 自动传递给每个回调函数的 src 和 event 输入之外,还可以用其他输入参数声明回调函数。使用元胞数组或匿名函数将这些输入参数传递给回调函数。
示例:使用回调输入参数的文字云应用
在文字云应用中,要在 App 用户按下按钮时共享 App 数据,请将该数据传递给 ButtonPushedFcn 回调函数。
定义名为 createWordCloud 的 ButtonPushedFcn 回调函数,以根据文本区域中的文本绘制文字云。createWordCloud 函数需要在点击按钮时访问文本框的值。它还需要访问面板容器以在其中绘制数据。为了提供这种访问,除了必需的 src 和 event 参数之外,还要定义 createWordCloud 以接受文本区域和面板作为输入参数。
function createWordCloud(src,event,txt,pnl)
% Code to plot the word cloud
end
对 createWordCloud 回调函数赋值,并在文本区域和面板中传递,方法是将 ButtonPushedFcn 指定为包含 createWordCloud 句柄的元胞数组,后跟其他输入参数。
btn.ButtonPushedFcn = {@createWordCloud,txt,pnl};
要运行此示例,请将 shareAsInput 函数保存到 MATLAB 路径中名为 shareAsInput.m 的文件中。
function shareAsInput
% Create figure and grid layout
fig = uifigure;
gl = uigridlayout(fig,[2,2]);
gl.RowHeight = {'1x',30};
gl.ColumnWidth = {'1x','2x'};
% Create and lay out text area
txt = uitextarea(gl);
txt.Layout.Row = 1;
txt.Layout.Column = 1;
% Create and lay out button
btn = uibutton(gl);
btn.Layout.Row = 2;
btn.Layout.Column = 1;
btn.Text = "Create Word Cloud";
% Create and lay out panel
pnl = uipanel(gl);
pnl.Layout.Row = [1 2];
pnl.Layout.Column = 2;
% Assign button callback function
btn.ButtonPushedFcn = {@createWordCloud,txt,pnl};
end
% Process and plot text
function createWordCloud(src,event,txt,pnl)
val = txt.Value;
words = {};
for k = 1:length(val)
text = strsplit(val{k});
words = [words text];
end
c = categorical(words);
wordcloud(pnl,c);
end
创建嵌套回调函数
最后,可以在编程式 App 的主函数内嵌套回调函数。这样做时,嵌套的回调函数将会与主函数共享工作区。因此,嵌套的函数可以访问在主函数中定义的所有 UI 组件和变量。
示例:使用嵌套回调的文字云应用
在文字云应用中,要在 App 用户按下按钮时共享 App 数据,请将按钮回调函数嵌套在主 App 函数中。定义名为 createWordCloud 的 ButtonPushedFcn 回调函数,以根据文本区域中的文本绘制文字云。createWordCloud 函数需要在点击按钮时访问文本框的值。它还需要访问面板容器以在其中绘制数据。要提供这种访问,请在主 nestCallback 函数中定义 createWordCloud。嵌套函数可以访问存储文本区域和面板组件的 t 和 p 变量。
要运行此示例,请将 nestCallback 函数保存到名为 nestCallback.m 的文件中,然后运行它。
function nestCallback
% Create figure and grid layout
fig = uifigure;
gl = uigridlayout(fig,[2,2]);
gl.RowHeight = {'1x',30};
gl.ColumnWidth = {'1x','2x'};
% Create and lay out text area
t = uitextarea(gl);
t.Layout.Row = 1;
t.Layout.Column = 1;
% Create and lay out button
b = uibutton(gl);
b.Layout.Row = 2;
b.Layout.Column = 1;
b.Text = "Create Word Cloud";
% Create and lay out panel
p = uipanel(gl);
p.Layout.Row = [1 2];
p.Layout.Column = 2;
% Assign button callback function
b.ButtonPushedFcn = @createWordCloud;
% Process and plot text
function createWordCloud(src,event)
val = t.Value;
words = {};
for k = 1:length(val)
text = strsplit(val{k});
words = [words text];
end
c = categorical(words);
wordcloud(p,c);
end
end