Alin Andersen
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
,用于代码引用; - 控件属性(位置、字体、颜色等)可视化设置,也可代码动态修改.
- 每个控件都有唯一的
- GUIDE 提供图形化设计器,允许用户拖拽控件(如按钮、文本框、坐标轴等),在
-
事件驱动机制:以回调函数为核心
-
MATLAB GUIDE 使用回调函数(Callback)机制响应用户操作:
控件类型 回调函数(Callback) 触发条件 pushbutton
pushbutton_Callback
用户点击按钮 edit
edit_Callback
用户输入后回车/失焦 axes
绘图函数控制显示 显示图像/数据更新 menu
menu_Callback
用户点击菜单项 uitable
CellEditCallback
用户修改表格内容
-
-
handles
结构统一管理 GUI 数据- 存储所有控件的句柄(如
handles.edit1
) - 存储自定义变量(如
handles.currentMode
) - 使用
guidata(hObject, handles)
更新共享数据
- 存储所有控件的句柄(如
-
生命周期函数划分明确
-
函数名 用途说明 OpeningFcn
GUI 启动时执行,初始化界面和变量 OutputFcn
GUI 执行完毕后输出句柄(可忽略) CreateFcn
控件创建时执行,设置默认属性 xxx_Callback
控件操作时触发,执行响应逻辑
-
-
典型设计流程
- 界面设计为中心:使用 GUIDE 拖拽设计界面
- 控件命名为基础:合理设置
Tag
便于代码管理 - 回调驱动交互:为控件定义响应逻辑函数
- 状态统一管理:通过
handles
管理变量和控件状态 - 分离布局与逻辑:界面设计和功能逻辑相对独立
-
小结
MATLAB GUIDE 的设计哲学是“可视化构建 + 回调驱动 + 状态集中管理”,让用户通过拖拽+编程的方式快速构建交互式图形应用。
示例程序(多界面APP)
以一个多界面APP为演示,演示GUI开发过程.
项目需求
实现一个三界面APP,各界面功能总结如下:
- 界面1:输入界面
- 要求在程序开始运行时弹出对话框,允许对界面1的样式进行切换.
- 样式1:可进行设计变量1、设计变量2的输入.
- 样式2:可进行设计变量3、设计变量4的输入.
- 两样式互斥.在弹出的对话框中完成选择后,样式在后续运行全程中不再可变.
- 要求在程序开始运行时弹出对话框,允许对界面1的样式进行切换.
- 界面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.
- 具体原因见”交互逻辑-程序初始设置”一节.
- 重要提示:此处的width与height值最好设置为目标窗口大小的2倍.
- 禁用缩放:在顶部菜单栏”工具”->“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_guihandles.output = hObject;
% Update handles structureguidata(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');endguidata(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.mfunction [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.mfunction [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);endguidata(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/