找回密码
 注册
关于网站域名变更的通知
查看: 586|回复: 1
打印 上一主题 下一主题

如何在Simulink环境中添加配置自定义菜单

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-2-6 09:44 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
9 t' r& b( j1 X+ \
写这个帖子主要是因为之前恒润科技给单位开发一个工具软件,需要和Simulink深度结合。但是在提需求的时候,他们坚定的说不能自定义Simulink配置环境(换句话说就是不能和Simulink整合,只能提供单独的工具),且已经咨询Mathworks,说没法在Simulink中添加自定义菜单等。
& C( G5 B6 P: o9 F1 h7 w& d# y* u  Z) [6 j+ ^. e/ U5 j
先预览下效果图,给大家一个感性的认识:- X! f* `+ H& C. _  t

  U9 I7 Q( {2 U2 }( ]另外这里提供本文用到的sl_customization函数
9 k0 F7 B! ?$ n% N1 |$ h: I
. d, V( D4 ~* v* h' S其实本文中涉及的技术,可以在Simulink的公开文档轻易找到,只是大家没有注意而已!另外本文中讨论的技术,不仅仅可以修改Simulink的菜单,还可以修改Simulink中很多环境配置,比如对话框控制、库浏览器、Simulink首选项等很多方面。本文仅以自定义Simulink菜单做抛砖引玉的作用!9 y- C, [& _8 l4 s
# K+ J0 H/ T2 r. }
在Simulink编辑器和Stateflow编辑中,可以在以下列表中添加菜单或命令:
2 E8 r3 G5 p2 k# Y* _/ p: y5 l( U3 f$ U; a
  • 顶级菜单的尾部
  • 右键菜单的首部或尾部
  • 工具条
    % ?6 S! z. X+ Y% N5 Y3 b  [' M

+ O! T; P4 H& ^% f, p1、注册用户界面自定义(Registering User InteRFace Customizations)
/ b% K& @+ S4 e+ v( h. P) J" e首先在MATLAB的搜索路径下,添加一个sl_customization()函数,简单说,此函数就是告诉Simulink您希望对Simulink环境做哪些修改。function sl_customization()函数接受一个输入参数cm,cm是一个自定义管理对象( customization manager object)。cm对象中内置了一些进行环境自定义的方法。启动Simulink的时候,程序会自动加载sl_customization文件。
" H  _1 l! H3 r. R+ w/ w  h
  • function sl_customization(cm)
  • % 用于自定义Simulink环境配置# Z# m* M3 I0 S
3 ~8 [+ g+ }( `" [6 O

9 E& h' [$ b; |2、添加自定义菜单函数(addCustomMenuFcn)% p! ?1 \8 v2 Y5 }
定制菜单主要用到cm对象的addCustomMenuFcn和addCustomFilterFcn两个方法。
! W* d( \; U2 F: b0 r9 B0 m
* E; s3 f6 \2 R( Z! U2 e(1)addCustomMenuFcn(stdMenuTag, menuSpecsFcn)方法。此方法的主要功能是,将menuSpecsFcn中自定义的条目添加到stdMenuTag菜单项目下,主要参数意义如下:7 v3 J6 K' K6 V# A
  • menuSpecsFcn:函数句柄,返回新增菜单项的创建函数,具体请看后面的例子。
  • stdMenuTag:字符串,指定需要进行修改的Simulink菜单。比如,希望在Simulink的Edit菜单下添加其它内容,那么stdMenuTag='Simulink:EditMenu',这个时候有人估计会疑问,既然Edit菜单stdMenuTag都那么复杂,那怎么知道其它菜单的stdMenuTag?其实很简单,在CommandWindows中执行如下命令
    ; E& i2 P( T/ g# L  ]+ Y
  • cm = sl_customization_manager;
  • cm.showWidgetIdAsToolTip=true;
    8 {4 a5 N7 A3 k8 _* c3 ]6 E( ?; ^
" ]3 ?& l  E4 }) k4 u: s  Z! c

6 l2 }) U+ d7 V' q1 p* T+ W6 d此时Simulink界面将变成如下样子,在原有菜单旁边会自动显示Simulink已有菜单的stdMenuTag
4 w( [" V- c; _+ T8 Y& Y, j- a
( a6 u* v/ _0 u4 e* R  \! |
: J8 R$ p0 Y- a; I# _9 W7 ^6 U
; `& o" m" r5 W) L( G当您不需要显示那个stdMenuTag时,在命令窗口执行) w$ t  {* l& J, e$ J
  • cm.showWidgetIdAsToolTip=false;" A  R8 h# J5 f) E' H, B- d

0 `/ o) b! K2 ^" o7 l* {( |(1)addCustomFilterFcn(stdMenuItemID, filterFcn)方法。该方法主要是用于,禁用或激活stdMenuItemID菜单。本文不大算详细介绍,感兴趣的朋友可以看看帮助文档。
3 k! G7 K0 B2 h* m! x8 z. u" R( T# u$ O8 Q0 D2 }3 i5 h6 k
因此文件中的代码重新修改如下:. k; S& G# h  l0 A: n7 H0 O
  • function sl_customization(cm)
  • % 用于自定义Simulink环境配置
  • % 告诉Simulink根据MenuWeWantAdd()返回参数中指定的函数
  • % 在'Simulink:EditMenu'菜单下添加新建菜单
  • cm.addCustomMenuFcn('Simulink:EditMenu',@MenuWeWantAdd)9 {. Y' d/ G* S7 A9 n8 D3 j

* g  a; K9 [- H4 \* {+ V7 J" R* {4 U2 P' ?# P( Z
3、定义新增菜单创建函数(Define Menu Create Function)
( v: k  Z/ Q2 z0 c在第二步中,告诉Simulink根据MenuWeWantAdd()返回参数中指定的函数来创建新菜单项,但是到底是使用哪些函数以及添加哪些菜单我们还米有定义。因此在sl_customization.m文件中继续添加如下代码:$ I5 ~( T8 f1 y3 M! e8 C" W/ g! `: A" T
  • function schemaFcns=MenuWeWantAdd(callbackInfo)
  • % 返回用于创建新增菜单的函数,必须接受一个callbackInfo输入参数
  • % 告诉Simulink分别使用下面的函数,来创建每个新增菜单项
  • schemaFcns={...
  •    @CreateNewMenu1 % 新增第1个菜单的函数
  •    @CreateNewMenu2 % 新增第2个菜单的函数
  •   @CreateNewMenu3};  % 新增第3个菜单的函数
    % C5 L; `+ b- x5 I2 D
$ `# f1 g2 L  y7 H% \; o- {: u

7 F, H$ }6 L: U2 ]& s4 w其中MenuWeWantAdd()函数就是告诉Simulink通过哪些函数来创建菜单。
4 w# A; z0 }, v( O% D3 w9 J( q+ _; ^1 u% H7 }  H" O# T7 c
其中的输入参数callbackInfo,是一个Callback Info对象,包含以下几个属性
- S' k$ R; g7 i7 C( d
; A4 T* l$ d% ]# v
! k3 f8 X; @# r8 K3 {9 t
属性说明
uiObject句柄,被点击菜单的父对象,Simulink编辑器或Stateflow编辑器
model句柄,当前编辑器中显示的Simulink模型
userdata

: b# _% X  @  k. E9 O# a8 g2 l0 N$ _# C, O1 K3 P" ~- U
       - U5 S/ W$ o1 G
4、定义新增Action菜单项(Define Action Menu Items)
* y( I& I" c- o0 {; [' ^* N虽然现在已经知道使用CreateNewMenu1()等函数来创建自定义菜单,但到底是什么菜单呢?,因此需要继续在sl_customization.m文件中添加如下代码:2 P) P5 B. Q$ E& J6 D: N2 {
  • function schema=CreateNewMenu1(callbackInfo)
  • % 用来创建NewMenu1菜单,必须接受一个callbackInfo输入参数
  • % 创建一个schema对象的实例,用于定义新增菜单的内容
  • schema=sl_action_schema; % Action Schema Object
  • % 指定菜单的显示名称,必须
  • schema.label = '新增Action菜单';
  • % 指定菜单响应函数,必须,可以是字符串,函数句柄或者cell数组
  • schema.callback = @NewMenu1Callback;
  • % 设置用户数据,非必须
  • schema.userdata = '';
  • function NewMenu1Callback(callbackInfo)
  • % 点击NewMenu1菜单时的响应函数,必须接受一个callbackInfo输入参数
  • msgbox('新增Action菜单,被临幸了!')' Y: N7 ^1 r! F; l8 x
3 ?9 ~- z( S9 X2 A( W

# k9 r7 [# v! M/ T/ v+ x" _- v* oAction Schema对象有以下属性
  v2 A  W$ o; X! H  ^( c
; c; G! Z* g, a' U7 S7 g
属性取值说明
tag字符串,可选菜单的唯一标识符,类似于Simulink:EditMenu的作用
label字符串,必须菜单的显示名称
state字符串,可选,只能以下三个取值 'Enabled'(默认)、'Disabled'、'Hidden'
statustip字符串,可选当鼠标移动到菜单上时,状态栏显示的提示文本
userdata任意数据,可选用户之定义数据
accelerator字符串,可选,例如,'CTR+K'菜单快捷键
callback字符串或函数句柄,必须点击菜单时的回调函数
autoDisableWhen字符串,可选,只能以下三个取值'Locked'(默认)、'Busy'、'Never'什么时候自动禁用菜单

; S4 u! K4 ]/ b1 ^% l
% m$ D: s5 T/ F5 I! Q+ ]5、添加Toggole菜单按钮(Toggle Schema Object)
5 x  p1 {/ j+ n. E7 P0 |其实在第4步中定义的是Action Schema Object,也是点击菜单,当点击菜单时响应相应的回调,但是菜单的形状不发生变化。而Toggle Schema Object在点击以后会发生形状变化,比如点击以后外形会凹陷下去,或者在菜单前面有一个√。
/ K4 f% I# x+ ]8 T# e' Q. o" c5 d0 l2 g
Toggle Schema Object和Action Schema Object的属性基本一致,只是Toggle对象多了一个checked属性,当摁下时,checked=='on',否则checked=='off'(默认)。另外Toggle对象是使用sl_toggle_schema创建实例的。# @' B  l* O3 i& w+ @- y0 }7 M; P
  • function schema=CreateNewMenu2(callbackInfo)
  • % 用来创建NewMenu2菜单,必须接受一个callbackInfo输入参数
  • % 创建一个schema对象的实例,用于定义新增菜单的内容
  • schema=sl_toggle_schema; % 注意这里是一个Toggle
  • % 指定菜单的显示名称,必须
  • schema.label = '新增Toggle菜单';
  • % 指定菜单响应函数,必须
  • schema.callback = @NewMenu2Callback;
  • % 设置用户数据,非必须
  • schema.userdata = '';
  • function NewMenu2Callback(callbackInfo)
  • % 点击NewMenu2菜单时的响应函数,必须接受一个callbackInfo输入参数
  • msgbox('新增Toggle菜单,被临幸了!')
      X+ W2 {# t& @7 x$ l8 }

$ r/ Y" q# ?$ ]2 |
' m8 {- B; I0 n/ q6、定义多级子菜单(Container Schema Object)
, X- `; A2 p( j( ]5 L. J第5和6步都是添加一个菜单项,下面尝试添加一个包含子菜单的项目试试。这个子菜单叫做Container Schema Object,使用sl_container_schema进行实例创建。Container Schema Object和前面两个对象属性基本相似,包含两个特殊属性:
, g8 H7 t8 g$ Q$ c6 E$ n0 l1 Z2 Y! e8 s/ q! P2 b; K
(1)childreNFCns6 b7 G8 v: k5 X6 Y6 h$ r4 f
Cell数组,指定创建子菜单函数的列表,等同于第2步中MenuWeWantAdd()的返回值。可以使用'separator'指定菜单之间的分割线。' a! a  _: Q* ]3 B" @
  • % 创建一个schema对象的实例,用于定义新增菜单的内容
  • schema=sl_container_schema; % 注意这里是一个container
  • % 子菜单创建函数,使用'separator'添加分割线
  • schema.childrenFcns={
  •    @CreateSubMenu1 % 子菜单创建函数1
  •    'separator' % 菜单之间的分隔符,快乐的分割线
  •    @CreateSubMenu2}; % 子菜单创建函数23 b# ~4 [" i% F& e) Q" I
7 g2 m! _5 c; S* X, `. P* x6 P
( {6 ]1 `5 f1 R7 f. \8 G# X
(2)generateFcn
2 q, K3 U( |) R5 Q函数句柄,相当于第2步中的@MenuWeWantAdd,该函数返回一个cell数组。
7 I: X5 s$ f7 a9 }0 f
  • % 创建一个schema对象的实例,用于定义新增菜单的内容
  • schema=sl_container_schema; % 注意这里是一个container
  • % 子菜单生成函数,注意当设置了generateFcn时,自动屏蔽childrenFcns
  • schema.generateFcn=@SubMenuWeWantAdd; % 返回生成子菜单的函数列表
    ' D0 c3 V: n: T, k  n9 R4 w
9 z8 u" g8 r' ?/ ^
! [0 j  \  Z- S3 x; k
请注意,generateFcn的优先权高于childrenFcns,当定义了generateFcn属性,那么childrenFcns属性自动被屏蔽。根据上面的说明,继续在sl_customization.m文件中添加如下代码:
4 H  T* K9 D9 ~+ I. m
  • function schema=CreateNewMenu3(callbackInfo)
  • % 用来创建NewMenu3菜单,必须接受一个callbackInfo输入参数
  • % 创建一个schema对象的实例,用于定义新增菜单的内容
  • schema=sl_container_schema; % 注意这里是一个container
  • % 指定菜单的显示名称,必须
  • schema.label = '新增Container菜单';
  • % 注意包含子菜单的项目是没有Callback属性的
  • % schema.callback = @NewMenu3Callback; % 该句无效
  • % 子菜单创建函数
  • schema.childrenFcns={
  •    @CreateSubMenu1 % 子菜单创建函数1
  •    'separator' % 菜单之间的分隔符,快乐的分割线
  •    @CreateSubMenu2}; % 子菜单创建函数2
  • % 子菜单生成函数,注意当设置了generateFcn时,自动屏蔽childrenFcns
  • schema.generateFcn=@SubMenuWeWantAdd; % 返回生成子菜单的函数列表
  • % 设置用户数据,非必须
  • schema.userdata = '';
  • function schemaFcns=SubMenuWeWantAdd(callbackInfo)
  • schemaFcns={
  •    @CreateSubMenu3 % 新增子菜单函数
  •    };
  • function schema=CreateSubMenu1(callbackInfo)
  • schema=sl_action_schema;
  • schema.label='新增子菜单1';
  • schema.callback='msgbox(''新增子菜单1,被临幸了!'')';
  • function schema=CreateSubMenu2(callbackInfo)
  • schema=sl_action_schema;
  • schema.label='新增子菜单2';
  • schema.callback='msgbox(''新增子菜单2,被临幸了!'')';
  • function schema=CreateSubMenu3(callbackInfo)
  • schema=sl_action_schema;
  • schema.label='新增子菜单3';
  • schema.callback='msgbox(''新增子菜单3,被临幸了!'')';, A8 a  Z5 Y5 L: H1 x

6 E) J4 K# b" A8 t# y0 C, d& D$ ?% ]* p7 c" R
7、让自定义立即菜单生效+ E/ K% I1 h" g- S" ^2 g. A8 x
好不容易编写好了上面的sl_customization.m,想立即看看效果,不过很惋惜的告诉您,您必须重启MATLAB,否不会生效。不过也可以在Command Windows中执行以下命令:1 B1 S. T& \' A' T1 ^9 }8 z8 r
  • sl_refresh_customizations% {( o6 c2 l9 [! L2 H8 V4 Z+ r; i
* P: Z8 K3 m3 h5 A5 o

; \1 w9 ?- D; G1 Q至于效果可以查看本文最头部的图片!. {& C9 D7 M+ ]/ ]% _
, @' u7 m/ E9 x; i. V+ B0 i/ x
请注意,在Window系统中,在sl_customization中设置断点,那么Simulink将不会执行设置断点的函数,因此如果想调试sl_customization文件,请使用命令行的形式,比如dbstop,千万不要在编辑器中直接设置断点。( o5 u8 L0 C2 m+ s+ O8 p2 X
  E4 L3 K7 z' Y
$ a+ |1 q1 s  k6 H2 D& t7 E

该用户从未签到

2#
发表于 2020-2-6 19:10 | 只看该作者
在Simulink环境中添加配置自定义菜单
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-11-23 21:45 , Processed in 0.156250 second(s), 26 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表