Simulink建模助手系列-进阶1
- [0. 前言](#0. 前言)
- [1. 主界面的实现](#1. 主界面的实现)
-
- [1.1 实现思路](#1.1 实现思路)
- [1.2 示例代码](#1.2 示例代码)
- [2. 集成到Simulink的右键菜单](#2. 集成到Simulink的右键菜单)
- 系列文章
-
- [- 基础篇:](#- 基础篇:)
- [- 进阶篇:](#- 进阶篇:)
0. 前言
之前的文章中介绍了一些提高建模效率的脚本代码,为了更方便地使用这些脚本,最好还是将其界面化,并且通过界面化可以提升与用户的交互,从而实现一些更为复杂的功能,因此部分功能将结合界面化进行该系列的分享。为了进行区分,偏向脚本级的、较简单的功能划分到基础篇,需要配合界面实现更复杂功能的将归到进阶篇。
作为进阶篇的第一篇文章,本文主要介绍建模助手主界面的基本实现,并将其集成到Simulink的右键菜单中。
1. 主界面的实现
1.1 实现思路
主界面采用uifigure的方式构建,Matlab虽然提供了appdesigner用于Ui界面的构建和开发,不过感觉不够灵活和过于臃肿,所以本文采用纯代码的方式构建Simulink建模助手的主界面。
主界面希望尽量简洁,主要包括三个区域:菜单栏,快捷操作区,状态栏。如图1所示,菜单栏主要用于放一些特殊功能,状态栏主要用于显示一些需要保持显示的消息,快捷操作区主要用于调用简单功能脚本的按钮,如基础篇中提到的功能可以封装成这些按钮的回调函数。

图1 主界面组成
考虑到主界面需要和Simulink模块同时可见,不能被Simulink的界面遮挡,因此主界面采用置顶显示设置,不过这也导致了一些问题,有些还没有得到解决(比如消息对话框不能用msgbox,否则会被主界面遮挡,只能用uialert,这也导致自动关闭对话框的方法没能实现),后面看看有什么办法可以解决,有大神知道的也可能评论区留言提示下。
操作区的布局采用uigridlayout,往uigridlayout里添加元素时,会根据设定好的行和列依次添加,如果是顺序添加元素,可以节省些代码量。
1.2 示例代码
matlab
function fig = app_slTool_mainUi(varargin)
% 全局设置
fontSize = 8;
% 主界面
fig = uifigure('Name','Simulink建模助手(示例)',...
'Resize','off', ...
'Pointer','hand', ...
'WindowStyle','alwaysontop');
bt_rows = 7; % 预设的按钮行数
fig.Position(3:4) = [300, bt_rows*30+20];
% 主界面布局
ly_main = uigridlayout(fig, ...
'RowHeight',{'1x','fit'}, ...
'ColumnWidth',{'1x'}, ...
'Padding',[1,1,1,1]*2);
%% 快捷按钮区
panel = uipanel(ly_main, ...
'Title', '', ...
'Fontsize', fontSize);
ly_panel = uigridlayout(panel, ...
'ColumnWidth', repelem({'1x'},3), ...
'RowHeight', repelem({'1x'},7), ...
'ColumnSpacing', 3, ...
'RowSpacing', 3, ...
'Padding', [3,1,3,1], ...
'Tooltip','');
% 第1行
uibutton(ly_panel, ...
'Text', 'Goto创建From', ...
'ButtonPushedFcn', @cb_createFromByGoto, ...
'Tooltip', '根据选中的Goto创建From。');
uibutton(ly_panel, ...
'Text', 'Goto创建Input', ...
'ButtonPushedFcn', '', ...
'Tooltip', '根据选中的Goto创建Input。');
uibutton(ly_panel, ...
'Text', '[预留按钮]', ...
'ButtonPushedFcn', '', ...
'Visible','off', ...
'Tooltip', '预留位置');
% 第2行
uibutton(ly_panel, ...
'Text', 'From创建Goto', ...
'ButtonPushedFcn', '', ...
'Tooltip', '根据选中的From创建Goto。');
uibutton(ly_panel, ...
'Text', 'From创建Output', ...
'ButtonPushedFcn', '', ...
'Tooltip', '根据选中的From创建Output。');
uibutton(ly_panel, ...
'Text', '[预留按钮]', ...
'ButtonPushedFcn', '', ...
'Visible','off', ...
'Tooltip', '预留位置');
% 第3行
uibutton(ly_panel, ...
'Text', '[预留按钮]', ...
'ButtonPushedFcn', '', ...
'Visible','off', ...
'Tooltip', '预留位置');
uibutton(ly_panel, ...
'Text', '[预留按钮]', ...
'ButtonPushedFcn', '', ...
'Visible','off', ...
'Tooltip', '预留位置');
uibutton(ly_panel, ...
'Text', '[预留按钮]', ...
'ButtonPushedFcn', '', ...
'Visible','off', ...
'Tooltip', '预留位置');
% 第4行
uibutton(ly_panel, ...
'Text', '批量连线', ...
'ButtonPushedFcn', '', ...
'Tooltip', '选中的模块批量连线,模块已有连线时无法连接');
uibutton(ly_panel, ...
'Text', 'G/F对齐连线', ...
'ButtonPushedFcn', '', ...
'Tooltip', '将选中的Goto和From模块与其信号线对齐。');
uibutton(ly_panel, ...
'Text', '智能调整Sub', ...
'ButtonPushedFcn', '', ...
'Tooltip', '对选中的子系统调整高度,对齐输入输出。');
%% 底部状态栏
statusBar = uilabel(ly_main, ...
'Text','就绪', ...
'HorizontalAlignment', 'left', ...
'Fontsize', fontSize);
%% 顶部主菜单
mHelp = uimenu(fig,'Text','帮助');
uimenu(mHelp, ...
'Text','关于',...
'MenuSelectedFcn','');
end
matlab
% 回调函数:根据Goto创建From
function cb_createFromByGoto(src,event)
currentSystem = gcs; % 获取当前模型
%获取选中的Goto
selectedGotos = find_system(currentSystem, ...
'SearchDepth', 1, ...
'Selected', 'on', ...
'BlockType', 'Goto');
% 逐个创建From
for i = 1:length(selectedGotos )
% 逐个获取Goto模块的信息
gotoPath = selectedGotos{i};
gotoTag = get_param(gotoPath, 'GotoTag');
gotoPos = get_param(gotoPath, 'Position');
parentPath = get_param(gotoPath,'Parent');
% 根据Goto的路径构建From
fromName = [parentPath,'/From'];
% 创建From模块
fromObj = add_block(['simulink/Signal Routing/From'], ...
fromName, 'MakeNameUnique','on');
% 设置Tag
set_param(fromObj, 'GotoTag', gotoTag);
% 计算From的位置和大小
x_move = 20;
x1 = gotoPos(3)+x_move; % From在Goto的右侧
x2 = x1+gotoPos(3)-gotoPos(1); % From继承Goto的宽度
fromPos = [x1, gotoPos(2), x2, gotoPos(4)];
% 设置Position
set_param(fromObj, 'Position', fromPos);
end
end
以上是主界面实现的基础方式,以及把根据Goto创建From的代码封装成按钮的回调函数。基础篇中介绍的脚本代码都可以封装成回调函数,填充到按钮中。如果有需要可以通过这种方式,打造专属的Simulink建模助手。
2. 集成到Simulink的右键菜单
主界面已经初具形状了,但是如何启动主界面呢?本文给出一种将其集成到Simulink的右键菜单的方法,并且能够避免重复打开多个主界面。
该方法需要创建一个名为sl_customization.m文件,并将其所在的路径添加到Matlab的搜索路径中,初次在matlab已经打开的情况下创建该文件时,添加好路径后,需要在命令行中运行sl_refresh_customizations,使新建的文件生效。
matlab
% sl_customization.m
function sl_customization(cm)
% 新增sl文件后刷新:运行命令 sl_refresh_customizations
% 增加菜单
try
cm.addCustomMenuFcn('Simulink:ContextMenu',@getMyMenuItems);
end
end
function schemaFcns = getMyMenuItems(callbackInfo)
schemaFcns = {@getItem1};
end
function schema = getItem1(callbackInfo)
schema = sl_action_schema;
schema.label = 'sl建模助手';
schema.callback = @run_slTool;
end
function run_slTool(callbackInfo)
persistent h
try
figure(h);
catch
h = app_slTool_mainUi();
end
end
成功添加后,我们可以在Simulink的右键菜单中找到主界面的启动按钮,如图2所示。

系列文章
- 基础篇:
Simulink建模助手系列-1【批量创建Goto和From】
Simulink建模助手系列-2【自动创建缺失的Goto】
Simulink建模助手系列-3【批量创建Inport和Outport】
Simulink建模助手系列-4【批量添加信号线】
Simulink建模助手系列-5【批量对齐模块】
Simulink建模助手系列-6【自动调整子系统高度和信号线】