3413 字
17 分钟
Matlab GUIDE构建多界面APP实践

封面来源:SSME(图文无关)

由于课题需要,使用MATLAB GUIDE构建GUI程序,特此记录.

MATLAB中的GUI设计工具#

常用的MATLAB GUI设计工具有:

  • (老)GUIDE:最传统的GUI设计工具.
    • GUI Deign Environment
    • 版本兼容性好:2016a版本前的唯一选择.
    • 控件少:仅限14种基础控件.
    • 界面单调:样式不可调.
    • 即将在未来版本弃用.
  • (新)APP DESIGNER:在MATLAB 2016a推出.
    • 控件丰富:提供了丰富的控件.
    • 简化设计:将很多常见功能打包成了控件,无需手写回调函数,大幅简化设计流程.
    • 版本兼容性较弱

两者的设计思想是类似的.出于兼容性考虑,本文选用GUIDE.

GUI设计思想#

为了让文章完整需要有这一段,但是懒了,让GPT帮忙一下.

  • 可视化布局 + 自动生成代码框架

    • GUIDE 提供图形化设计器,允许用户拖拽控件(如按钮、文本框、坐标轴等),在 .fig 文件中定义 GUI 布局,生成对应 .m 文件代码;
      • 每个控件都有唯一的 Tag,用于代码引用;
      • 控件属性(位置、字体、颜色等)可视化设置,也可代码动态修改.
  • 事件驱动机制:以回调函数为核心

    • MATLAB GUIDE 使用回调函数(Callback)机制响应用户操作:

      控件类型回调函数(Callback)触发条件
      pushbuttonpushbutton_Callback用户点击按钮
      editedit_Callback用户输入后回车/失焦
      axes绘图函数控制显示显示图像/数据更新
      menumenu_Callback用户点击菜单项
      uitableCellEditCallback用户修改表格内容
  • handles 结构统一管理 GUI 数据

    • 存储所有控件的句柄(如 handles.edit1
    • 存储自定义变量(如 handles.currentMode
    • 使用 guidata(hObject, handles) 更新共享数据
  • 生命周期函数划分明确

    • 函数名用途说明
      OpeningFcnGUI 启动时执行,初始化界面和变量
      OutputFcnGUI 执行完毕后输出句柄(可忽略)
      CreateFcn控件创建时执行,设置默认属性
      xxx_Callback控件操作时触发,执行响应逻辑
  • 典型设计流程

    1. 界面设计为中心:使用 GUIDE 拖拽设计界面
    2. 控件命名为基础:合理设置 Tag 便于代码管理
    3. 回调驱动交互:为控件定义响应逻辑函数
    4. 状态统一管理:通过 handles 管理变量和控件状态
    5. 分离布局与逻辑:界面设计和功能逻辑相对独立
  • 小结

    MATLAB GUIDE 的设计哲学是“可视化构建 + 回调驱动 + 状态集中管理”,让用户通过拖拽+编程的方式快速构建交互式图形应用。

示例程序(多界面APP)#

以一个多界面APP为演示,演示GUI开发过程.

项目需求#

实现一个三界面APP,各界面功能总结如下:

  • 界面1:输入界面
    • 要求在程序开始运行时弹出对话框,允许对界面1的样式进行切换.
      • 样式1:可进行设计变量1、设计变量2的输入.
      • 样式2:可进行设计变量3、设计变量4的输入.
      • 两样式互斥.在弹出的对话框中完成选择后,样式在后续运行全程中不再可变.
  • 界面2:输出界面1
    • 将设计结果(结果变量1、结果变量2)以数值形式呈现.
  • 界面3:输出界面2
    • 将设计结果(列表数据1)以图表形式呈现.

输入/输出#

  • 输入:两组互斥的设计变量.
    • 均在界面1中读入.
    • 变量组1:设计变量1、设计变量2.
    • 变量组2:设计变量3、设计变量4.
  • 输出:一组数值变量+一组列表数据.
    • 数值变量在界面2中输出,列表数据在界面3中输出.
    • 数值变量:结果变量1、结果变量2.
    • 列表数据:列表数据1.
      • 一个n*3矩阵.
      • 第一列代表时间t,第二、三列为对应时刻的结果变量3与结果变量4.

架构设计#

  • 基于MATLAB GUIDE开展设计.
  • 界面切换:使用”菜单编辑器”控制Panel可见性实现.
  • 界面1的样式切换:通过控制两个独立Panel可见性实现.
  • 数值变量显示:使用”静态文本”控件实现.
  • 列表数据显示:使用”表”与”坐标区”控件实现.

界面设计#

启动GUIDE#

  • 在matlab命令行中输入”guide”(不含引号).
  • 开启后,先通过”文件”->“另存为”,将文件存储到合适路径.
  • 此时,会在对应路径下生成一个”文件名.fig”以及一个”文件名.m”文件,分别对应窗口设计与回调函数.

界面基本属性#

  • 修改名称
    • 在初始界面,打开”属性检查器”.
      • 属性检查器
    • 修改Name字段:找到”Name”字段,将内容改为期望的窗体名称(本文为”多界面APP”),回车确定.
    • 修改Tag字段:回调函数中的控件名称.
  • 修改窗口大小
    • 修改Unit字段:仍在属性检查器中,首先修改”Units”字段值为”pixels”;
    • 修改Position字段:点开左侧隐藏菜单,x=y=0,按需设置width与height.
      • 重要提示:此处的width与height值最好设置为目标窗口大小的2倍.
        • 如期望窗口大小为640*360,则应将两者设置为1280*720.
        • 具体原因见”交互逻辑-程序初始设置”一节.
    • 禁用缩放:在顶部菜单栏”工具”->“GUI选项”,“调整大小的方式”确认为”不可调整大小”.
  • 本节结束

菜单设计#

  • 打开”目录编辑器”

    • 目录编辑器
  • 添加母菜单

    • 点击左上角”新建菜单”,并进一步选择新创建的”Untitled 1”对象.右侧属性栏目中:
    • 文本:将会在界面上显示的名称,此处填写”界面切换”;
    • 标记:回调函数中的控件名称,填写”InterfaceSwitch”.
  • 添加子菜单

    • 点击左上角”新建菜单项”,创建三个子菜单栏目.

    • 相应修改文本与标记.

    • 序号文本标记
      1参数输入MotorInput
      2数值输出NumericOutput
      3图表输出FigureOutput
    • 此时的目录编辑器及对应的运行时样式如图.

    • 目录设置后
  • 本节结束

面板(Panel)设计#

  • 程序的界面/样式切换本质是通过切换控件可见性实现的.

  • 面板作为容器,可以实现对一组控件可见性的集中控制,方便实现切换逻辑.

  • 添加面板

    • 从左侧控件库中,将面板(Panel)控件拖放到主界面.
    • 在拖放形成的面板上,右键进入”属性检查器”.
      • 修改名称字段.
      • 修改大小与Position字段(注意此处的width与height值无需×2).
      • 修改Tag:回调函数中的代号.
    • 呈现效果为面板位于整个Figure的左下角,占据画幅1/4.
    • 将面板复制出三份,各自修改Name和Position字段,使其互不重叠,且完全占据整个Figure.
      • 需保证各Panel间没有隶属关系,可通过界面上方”对象查看器”查看,如下图说明操作正确.
      • 独立面板
  • 输入面板

    • 在”变量输入_样式1”面板中,添加两组”静态文本”与”可编辑文本”控件.

    • 静态文本用于提示输入参数名称,可编辑文本用于获取参数.

    • 静态文本控件

      • String字段:显示的文本,按需.
      • FontSize字段:字号,按需.
      • Tag字段:回调函数中的代号,按需.
    • 可编辑文本控件

      • String字段:显示的文本,清空.
      • FontSize字段:字号,按需.
      • Tag字段:回调函数中的代号,按需.
    • 做一下对齐,设置完毕后如图.

    • 输入设置完成
    • 相似地,对”变量输入_样式2”面板进行设置.

  • 输出面板

    • 数值输出
      • 添加”普通按钮”控件用以开始计算.
        • 同样修改String,FontSize和Tag三个字段.
      • 采用”静态文本”进行输出,设置方法同输入面板
    • 图表输出
      • 拖放一个”表”与一个”坐标区”控件到”图表输出”面板.
      • 同样对Tag字段进行设置.
    • 最终结果如图.
    • 面板设置完毕

交互逻辑#

设计合适的回调函数,使各组件协调运作.

首先,打开GUIDE自动生成的.m文件.

程序初始设置#

% 本节将内容添加在GUIDE生成.m文件"[FileName]_OpeningFcn(...)"函数末尾(其中[FileName]是项目文件名称),实现了各面板的叠放与参数输入样式的选择.
% OpeningFcn会在程序内部初始化完毕,即将显示的时候执行.
% 因此其内部可以在用户无感知的前提下,调用所有控件的方法.
% --- Executes just before motor_gui is made visible.
function motor_gui_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to motor_gui (see VARARGIN)
% Choose default command line output for motor_gui
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% UIWAIT makes motor_gui wait for user response (see UIRESUME)
% uiwait(handles.Figure_Main);
% 这里开始添加内容
% 1. 重设页面布局,将所有界面叠到一起.
% 如果在设计过程中就将各个面板叠在一起,改起来会非常不方便.
% 因此在设计时将界面平铺,再在这里把界面自动叠起来.
% 形如Panel_MotorInputTheme1的名称需要根据各控件的tag属性相应修改.
display_width = 640;
display_height = 360;
set(handles.Panel_MotorInputTheme1, 'Position', ...
[0, 0, display_width, display_height]);
set(handles.Panel_MotorInputTheme2, 'Position', ...
[0, 0, display_width, display_height]);
set(handles.Panel_NumericOutput, 'Position', ...
[0, 0, display_width, display_height]);
set(handles.Panel_FigureOutput, 'Position', ...
[0, 0, display_width, display_height]);
set(handles.Figure_Main, 'Position', ...
[0, 0, display_width, display_height]);
% 2. 获取输入样式
% 创建对话框
choice = questdlg('请选择输入样式:', '输入模式选择', '样式1', '样式2', '样式1');
switch choice
case '样式1'
handles.MotorInputMode = '1'; % handles中的变量可由所有回调函数共享.
set(handles.Panel_MotorInputTheme1, 'Visible', 'On'); % 样式1可见
set(handles.Panel_MotorInputTheme2, 'Visible', 'Off'); % 其它统统设置成不可见
set(handles.Panel_NumericOutput, 'Visible', 'Off');
set(handles.Panel_FigureOutput, 'Visible', 'Off');
case '样式2'
handles.MotorInputMode = '2';
set(handles.Panel_MotorInputTheme2, 'Visible', 'On'); % 样式2可见
set(handles.Panel_MotorInputTheme1, 'Visible', 'Off'); % 其它统统设置成不可见
set(handles.Panel_NumericOutput, 'Visible', 'Off');
set(handles.Panel_FigureOutput, 'Visible', 'Off');
otherwise
handles.MotorInputMode = '1';
set(handles.Panel_MotorInputTheme1, 'Visible', 'On'); % 样式1可见
set(handles.Panel_MotorInputTheme2, 'Visible', 'Off'); % 其它统统设置成不可见
set(handles.Panel_NumericOutput, 'Visible', 'Off');
set(handles.Panel_FigureOutput, 'Visible', 'Off');
end
guidata(hObject, handles); % 全局应用对MotorInputMode变量的更新.
% 设置完成.

菜单栏设置#

% 本节实现了程序左上角的菜单切换功能.
% 找到[MenuChoiceName]_Callback(...)函数,其中[MenuChoiceName]是"菜单设计"一节中的标记名称.
% 找不到的话,点开对象编辑器,找到对应的Menu条目,找到MenuSelectedFcn,点击函数签名左侧的图标,选择"是",让matlab创建一个.
function MotorInput_Callback(hObject, eventdata, handles)
switch handles.MotorInputMode
case '1'
set(handles.Panel_MotorInputTheme1, 'Visible', 'On'); % 样式1可见
set(handles.Panel_MotorInputTheme2, 'Visible', 'Off'); % 其它统统设置成不可见
set(handles.Panel_NumericOutput, 'Visible', 'Off');
set(handles.Panel_FigureOutput, 'Visible', 'Off');
case '2'
set(handles.Panel_MotorInputTheme2, 'Visible', 'On'); % 样式2可见
set(handles.Panel_MotorInputTheme1, 'Visible', 'Off'); % 其它统统设置成不可见
set(handles.Panel_NumericOutput, 'Visible', 'Off');
set(handles.Panel_FigureOutput, 'Visible', 'Off');
end
function NumericOutput_Callback(hObject, eventdata, handles)
set(handles.Panel_NumericOutput, 'Visible', 'On'); % 类似以上
set(handles.Panel_MotorInputTheme1, 'Visible', 'Off');
set(handles.Panel_MotorInputTheme2, 'Visible', 'Off');
set(handles.Panel_FigureOutput, 'Visible', 'Off');
function FigureOutput_Callback(hObject, eventdata, handles)
set(handles.Panel_FigureOutput, 'Visible', 'On');
set(handles.Panel_MotorInputTheme1, 'Visible', 'Off');
set(handles.Panel_MotorInputTheme2, 'Visible', 'Off');
set(handles.Panel_NumericOutput, 'Visible', 'Off');
% 设置完成.

实现计算逻辑&展示结果#

% 本节实现了外部.m计算文件的嵌入.
% 使用main_theme1和main_theme2两个函数,代表两种不同输入样式.
% 示例计算程序:main_theme1.m
function [motor_numeric_result, motor_list_result] = main_theme1(motor_design_variables_theme1)
% 用加减法生成数值结果
motor_numeric_result.res1 = motor_design_variables_theme1.var1 + ...
motor_design_variables_theme1.var2;
motor_numeric_result.res2 = motor_design_variables_theme1.var1 - ...
motor_design_variables_theme1.var2;
% 生成列表结果
motor_list_result = [linspace(0,10,11); linspace(0,20,11); linspace(0,30,11)]';
end
% 示例计算程序:main_theme2.m
function [motor_numeric_result, motor_list_result] = main_theme2(motor_design_variables_theme2)
% 用乘除法生成数值结果
motor_numeric_result.res1 = motor_design_variables_theme2.var1 * ...
motor_design_variables_theme2.var2;
motor_numeric_result.res2 = motor_design_variables_theme2.var1 / ...
motor_design_variables_theme2.var2;
% 生成列表结果
motor_list_result = [linspace(0,-10,11); linspace(0,-20,11); linspace(0,-30,11)]';
end
% 下面设置回调函数.
% 在[ButtonName]_Callback(...)中定义点击"开始计算"后的行为.
% 如果找不到,同样去对象管理器里创建一个.
function Button_NumericOutput_StartCalculate_Callback(hObject, eventdata, handles)
switch handles.MotorInputMode
case '1'
% 从theme1面板输入构建输入结构体
motor_design_variables_theme1.var1 = ...
str2double(get(handles.Text_MotorInputTheme1_Var1, 'String'));
motor_design_variables_theme1.var2 = ...
str2double(get(handles.Text_MotorInputTheme1_Var2, 'String'));
% 展开计算
[handles.motor_numeric_result, handles.motor_list_result] = ...
main_theme1(motor_design_variables_theme1);
case '2'
% 从theme2面板输入构建输入结构体
motor_design_variables_theme2.var1 = ...
str2double(get(handles.Text_MotorInputTheme2_Var1, 'String'));
motor_design_variables_theme2.var2 = ...
str2double(get(handles.Text_MotorInputTheme2_Var2, 'String'));
% 展开计算
[handles.motor_numeric_result, handles.motor_list_result] = ...
main_theme2(motor_design_variables_theme2);
end
guidata(hObject, handles); % 全局应用对计算结果的更新.
% 展示结果
set(handles.Text_NumericOutput_Var1, 'String', ...
num2str(handles.motor_numeric_result.res1));
set(handles.Text_NumericOutput_Var2, 'String', ...
num2str(handles.motor_numeric_result.res2));
% 提示:可额外定义"ColumnName"字段以修改列标题.
set(handles.Uitable_FigureOutput, 'Data', handles.motor_list_result);
plot(handles.Axes_FigureOutput, ...
handles.motor_list_result(:,1), handles.motor_list_result(:,2));
% 设置完成.

EX 修改参数后清除计算结果#

% 在修改输入参数后,将所有计算结果全部清除,避免参数与结果间的不一致.
% 先在GUIDE的.m文件中创建一个公用的清理函数.
function clear_all_outputs(hObject, eventdata, handles)
set(handles.Text_NumericOutput_Var1, 'String', "");
set(handles.Text_NumericOutput_Var2, 'String', "");
set(handles.Uitable_FigureOutput, 'Data', {});
cla(handles.Axes_FigureOutput, 'reset');
% 在[TextName]_Callback(...)中调用清理函数.
% 其中[TextName]为对应文本框的Tag名称.
% 该函数会在文本框内容发生变化时调用.
function Text_MotorInputTheme1_Var1_Callback(hObject, eventdata, handles)
clear_all_outputs(hObject, eventdata, handles);
% 给四个文本框都加上.
function Text_MotorInputTheme1_Var2_Callback(hObject, eventdata, handles)
clear_all_outputs(hObject, eventdata, handles);
function Text_MotorInputTheme2_Var1_Callback(hObject, eventdata, handles)
clear_all_outputs(hObject, eventdata, handles);
function Text_MotorInputTheme2_Var2_Callback(hObject, eventdata, handles)
clear_all_outputs(hObject, eventdata, handles);
% 设置完成.

大功告成!

小结#

本文介绍了使用GUIDE创建一个多界面APP的过程,实现了MATLAB GUIDE功能的入门.

GUIDE(GUI设计环境)与guide(向导)相通,令人忍俊不禁(×

Matlab GUIDE构建多界面APP实践
https://www.lithium-hydroxide.space/posts/250717_matlab_guide_tutorial/
作者
LiH
发布于
2025-07-17
许可协议
CC BY-NC-SA 4.0