|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
; K5 ^& u9 E7 ]9 t, f* D1 b写这个帖子主要是因为之前恒润科技给单位开发一个工具软件,需要和Simulink深度结合。但是在提需求的时候,他们坚定的说不能自定义Simulink配置环境(换句话说就是不能和Simulink整合,只能提供单独的工具),且已经咨询Mathworks,说没法在Simulink中添加自定义菜单等。5 Y9 |4 f4 C; |: r; p5 i0 H: i
# G6 ^& `5 p' P8 c2 Y$ x* h
先预览下效果图,给大家一个感性的认识:
" k4 s0 l& k* c% t0 T$ n
. @' z6 k; v1 `. h另外这里提供本文用到的sl_customization函数
$ x" P9 v, n% [7 {1 o
8 F1 K3 e) E" s! V$ \ j$ R其实本文中涉及的技术,可以在Simulink的公开文档轻易找到,只是大家没有注意而已!另外本文中讨论的技术,不仅仅可以修改Simulink的菜单,还可以修改Simulink中很多环境配置,比如对话框控制、库浏览器、Simulink首选项等很多方面。本文仅以自定义Simulink菜单做抛砖引玉的作用!
) O; r& t& T0 V- X; k0 j: {$ @" J, f
/ k" t" h4 e8 x% K# v在Simulink编辑器和Stateflow编辑中,可以在以下列表中添加菜单或命令:; d" e6 ?) e, g8 E) S
4 k1 F o* J" y: t& h& P- 顶级菜单的尾部
- 右键菜单的首部或尾部
- 工具条3 j3 P* I. p( w# ~
! l, z7 V5 E# t, ]) {
1、注册用户界面自定义(Registering User InteRFace Customizations)
" r: C' Y- q/ V. n3 t1 @3 I首先在MATLAB的搜索路径下,添加一个sl_customization()函数,简单说,此函数就是告诉Simulink您希望对Simulink环境做哪些修改。function sl_customization()函数接受一个输入参数cm,cm是一个自定义管理对象( customization manager object)。cm对象中内置了一些进行环境自定义的方法。启动Simulink的时候,程序会自动加载sl_customization文件。. ]9 p! j7 h# }- o3 f
- function sl_customization(cm)
- % 用于自定义Simulink环境配置
1 g" B& ?6 V; c 8 @7 d. Z l/ y& A" u5 v
7 ] q: E; |/ x1 |% T2、添加自定义菜单函数(addCustomMenuFcn)
, I" c* ^5 r( ` E定制菜单主要用到cm对象的addCustomMenuFcn和addCustomFilterFcn两个方法。& Y1 m0 D/ H+ U H& c1 a4 [ z
2 ~% A& v$ W- l4 j( s6 `: J- z5 H(1)addCustomMenuFcn(stdMenuTag, menuSpecsFcn)方法。此方法的主要功能是,将menuSpecsFcn中自定义的条目添加到stdMenuTag菜单项目下,主要参数意义如下:% m; c4 s# ]- b' W- A6 s5 L
- menuSpecsFcn:函数句柄,返回新增菜单项的创建函数,具体请看后面的例子。
- stdMenuTag:字符串,指定需要进行修改的Simulink菜单。比如,希望在Simulink的Edit菜单下添加其它内容,那么stdMenuTag='Simulink:EditMenu',这个时候有人估计会疑问,既然Edit菜单stdMenuTag都那么复杂,那怎么知道其它菜单的stdMenuTag?其实很简单,在CommandWindows中执行如下命令
- K! N/ I7 v& h
- cm = sl_customization_manager;
- cm.showWidgetIdAsToolTip=true;
/ C. `( o4 l, G# `
# X' l& [/ k6 h* [- ]' I6 t5 a. u( ]3 L0 P
此时Simulink界面将变成如下样子,在原有菜单旁边会自动显示Simulink已有菜单的stdMenuTag8 u& ]" H: r+ }. }" D
2 X4 B" J6 K9 K( A) B. e# o( ~9 v
% N* n8 L- r! k% k6 |1 ^, I
5 d i1 Z1 Z2 T# o6 `3 Z3 N当您不需要显示那个stdMenuTag时,在命令窗口执行
! V7 E( H9 {7 D4 X- cm.showWidgetIdAsToolTip=false;
! [8 r" ]5 q, l1 B) e$ B3 K2 _ 9 X' R# p! a: i" T9 k
(1)addCustomFilterFcn(stdMenuItemID, filterFcn)方法。该方法主要是用于,禁用或激活stdMenuItemID菜单。本文不大算详细介绍,感兴趣的朋友可以看看帮助文档。) ^( r: q( X+ ~$ Q0 S
0 d: @4 [/ _6 l8 q, i! i
因此文件中的代码重新修改如下:
6 X; E. n* {4 B1 k: K& V) l- function sl_customization(cm)
- % 用于自定义Simulink环境配置
- % 告诉Simulink根据MenuWeWantAdd()返回参数中指定的函数
- % 在'Simulink:EditMenu'菜单下添加新建菜单
- cm.addCustomMenuFcn('Simulink:EditMenu',@MenuWeWantAdd)8 ]) Z/ v! \. e, e/ J
3 G5 n8 }- q! ^& O9 z6 M& R3 b# [
, d9 U* V. j- t6 ~3、定义新增菜单创建函数(Define Menu Create Function)
+ u6 \0 [, A4 G在第二步中,告诉Simulink根据MenuWeWantAdd()返回参数中指定的函数来创建新菜单项,但是到底是使用哪些函数以及添加哪些菜单我们还米有定义。因此在sl_customization.m文件中继续添加如下代码:
& f$ P% @3 j0 d+ N# k3 d- function schemaFcns=MenuWeWantAdd(callbackInfo)
- % 返回用于创建新增菜单的函数,必须接受一个callbackInfo输入参数
- % 告诉Simulink分别使用下面的函数,来创建每个新增菜单项
- schemaFcns={...
- @CreateNewMenu1 % 新增第1个菜单的函数
- @CreateNewMenu2 % 新增第2个菜单的函数
- @CreateNewMenu3}; % 新增第3个菜单的函数
7 r( a- Q6 d4 g/ T 7 H3 Z4 j Q2 x; M
; ]6 d! }1 _! o; c$ Y其中MenuWeWantAdd()函数就是告诉Simulink通过哪些函数来创建菜单。
2 J2 z: t# D* N" V$ S( L, P, W8 s1 ~) e1 H8 P3 B9 l
其中的输入参数callbackInfo,是一个Callback Info对象,包含以下几个属性" Y; q6 P' ^# m& q" u8 F3 A; V- a
) n2 [/ U2 w4 X5 n3 C _/ K
# |1 X) G1 l2 X+ p7 [. o
| 属性 | 说明 | | uiObject | 句柄,被点击菜单的父对象,Simulink编辑器或Stateflow编辑器 | | model | 句柄,当前编辑器中显示的Simulink模型 | | userdata | | 7 b% @2 _8 z6 n% V/ ^2 c' }
3 j3 ~. g% A- X1 k8 c
: V2 B9 a; I) J+ J4、定义新增Action菜单项(Define Action Menu Items)% b, ^$ z1 b2 ]% f
虽然现在已经知道使用CreateNewMenu1()等函数来创建自定义菜单,但到底是什么菜单呢?,因此需要继续在sl_customization.m文件中添加如下代码:+ o! q" R5 E3 |5 w
- 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菜单,被临幸了!')
, N$ k- L. n4 x5 l1 u) m 8 P$ V7 [# |+ b- H* J/ b$ F3 o" Q3 l
: V; t0 p* }) Y* G0 B2 i! S
Action Schema对象有以下属性6 c8 K8 Q$ P x( Q, y
/ K& E, p7 g! s2 `8 ]3 e9 ]/ C6 ?; V' M" I| 属性 | 取值 | 说明 | | tag | 字符串,可选 | 菜单的唯一标识符,类似于Simulink:EditMenu的作用 | | label | 字符串,必须 | 菜单的显示名称 | | state | 字符串,可选,只能以下三个取值 'Enabled'(默认)、'Disabled'、'Hidden' | | | statustip | 字符串,可选 | 当鼠标移动到菜单上时,状态栏显示的提示文本 | | userdata | 任意数据,可选 | 用户之定义数据 | | accelerator | 字符串,可选,例如,'CTR+K' | 菜单快捷键 | | callback | 字符串或函数句柄,必须 | 点击菜单时的回调函数 | | autoDisableWhen | 字符串,可选,只能以下三个取值'Locked'(默认)、'Busy'、'Never' | 什么时候自动禁用菜单 |
: m. Y! f2 u' p+ L ?
( r% u8 r. r3 k( [5、添加Toggole菜单按钮(Toggle Schema Object)
- W5 L$ z- _) b' _其实在第4步中定义的是Action Schema Object,也是点击菜单,当点击菜单时响应相应的回调,但是菜单的形状不发生变化。而Toggle Schema Object在点击以后会发生形状变化,比如点击以后外形会凹陷下去,或者在菜单前面有一个√。
% b. w' B( r, A0 _7 D" @ a, z9 ~' l5 t$ E0 b1 `( n
Toggle Schema Object和Action Schema Object的属性基本一致,只是Toggle对象多了一个checked属性,当摁下时,checked=='on',否则checked=='off'(默认)。另外Toggle对象是使用sl_toggle_schema创建实例的。
+ P0 x/ A% S. | R9 }- 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菜单,被临幸了!'): @ ]6 A# d. n3 t$ v; M; G9 M
* f$ t3 F) @ Q2 t4 E! d8 i7 G
; @2 G9 w" p* q: D- q6、定义多级子菜单(Container Schema Object)5 e$ @; B6 y" ~- @9 U
第5和6步都是添加一个菜单项,下面尝试添加一个包含子菜单的项目试试。这个子菜单叫做Container Schema Object,使用sl_container_schema进行实例创建。Container Schema Object和前面两个对象属性基本相似,包含两个特殊属性:
& C% i% e+ X% Y( M( L; p5 g6 M1 L/ \' U/ c: B5 T" D9 y4 H4 d! E
(1)childreNFCns
\ D5 b" [$ _" w+ W. dCell数组,指定创建子菜单函数的列表,等同于第2步中MenuWeWantAdd()的返回值。可以使用'separator'指定菜单之间的分割线。
8 g1 x: f1 [ p; Z: m, D- % 创建一个schema对象的实例,用于定义新增菜单的内容
- schema=sl_container_schema; % 注意这里是一个container
- % 子菜单创建函数,使用'separator'添加分割线
- schema.childrenFcns={
- @CreateSubMenu1 % 子菜单创建函数1
- 'separator' % 菜单之间的分隔符,快乐的分割线
- @CreateSubMenu2}; % 子菜单创建函数2) _+ j$ V) x$ E5 e1 V
+ ?7 m# k+ C4 q: V5 T/ Y
3 k( S7 m( X x' e; H(2)generateFcn
" ~+ v# m' E7 d; ~# f6 Q函数句柄,相当于第2步中的@MenuWeWantAdd,该函数返回一个cell数组。7 c, s, ^& ]- x W& Q/ f- p6 J
- % 创建一个schema对象的实例,用于定义新增菜单的内容
- schema=sl_container_schema; % 注意这里是一个container
- % 子菜单生成函数,注意当设置了generateFcn时,自动屏蔽childrenFcns
- schema.generateFcn=@SubMenuWeWantAdd; % 返回生成子菜单的函数列表$ c: i9 v" a% Z3 ^" n
' G# I, Q: W" O5 Y2 A: C7 O1 Z3 M6 P8 w6 t/ a& c
请注意,generateFcn的优先权高于childrenFcns,当定义了generateFcn属性,那么childrenFcns属性自动被屏蔽。根据上面的说明,继续在sl_customization.m文件中添加如下代码:9 P8 k d2 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,被临幸了!'')';
# v. e: L Y) T3 n
' ]. C. k' ~) B; m0 j
* I2 c: h! }) m W7、让自定义立即菜单生效
( ~4 o4 l+ B1 F; N" K4 x好不容易编写好了上面的sl_customization.m,想立即看看效果,不过很惋惜的告诉您,您必须重启MATLAB,否不会生效。不过也可以在Command Windows中执行以下命令:
& d% I' d' d+ l, X4 |" L2 T4 _ D$ D- sl_refresh_customizations1 |# j; j1 U# \; B* [+ S3 M
3 D- p, B4 q; t1 u, ~9 c
* [ X+ W6 H4 [' Z& ~, o
至于效果可以查看本文最头部的图片!
( y1 J" p7 _' \% w, E
5 @6 x' n6 y3 C/ T! v$ z2 `请注意,在Window系统中,在sl_customization中设置断点,那么Simulink将不会执行设置断点的函数,因此如果想调试sl_customization文件,请使用命令行的形式,比如dbstop,千万不要在编辑器中直接设置断点。
7 m; s* Z" G4 X; I/ @
- e5 x. i6 ]! |7 e- C9 U) E8 N' R. \+ T) Z. v1 o! N* w' W. s6 U. i6 X, C. l
|
|