有时候我们需要级联菜单中前方可以勾选(√),来表示当前系统的某种状态,这就需要用到可以打勾的菜单。
先看最终效果:
下面我们首先来看看怎么在plugin.xml中配置该菜单:
假设我们要做一个类似于powerdesigner样的数据库设计工具,其中表格在对话框中的显示只能是一下三种之一:
1)只显示主键 2)只显示主外键 3)全部显示
所以我们希望可以主菜单“视图”下加一个“表格图形显示”的级联菜单,“表格图形显示”下面有三个子菜单,用来表示上面的三种显示状态,于是在plugin.xml中org.eclipse.ui.commands扩展点下先建三个Command,截图如下:
注意,我们在每个command下都添加了一个state的节点,用来记录其command的状态值,下面附上state节点的截图:
记住,一个command下建立多个state节点时,它们的id值是不能重复的,我们在id中写的org.eclipse.ui.commands.toggleState其实是系统中RegistryToggleState.STATE_ID所定义的值,我们在这三个command节点下添加的state节点id和class都是相同的,如果你想系统在运行时,默认选择一种表格显示方式,只需要在这个显示方式的command下的state节点中class改成org.eclipse.ui.handlers.RegistryToggleState:true就行了。这样,我们需要的三个Command就配置完了,附上其对应的xml内容:
<command
id="sunline.suncard.powerdesigner.commands.onlyshowprimarykey"
name="%onlyshowprimarykey">
<state
class="org.eclipse.ui.handlers.RegistryToggleState:false"
id="org.eclipse.ui.commands.toggleState">
</state>
</command>
<command
id="sunline.suncard.powerdesigner.commands.showprimaryandforeign"
name="%showprimaryandforeign">
<state
class="org.eclipse.ui.handlers.RegistryToggleState:false"
id="org.eclipse.ui.commands.toggleState">
</state>
</command>
<command
id="sunline.suncard.powerdesigner.commands.showall"
name="%showall">
<state
class="org.eclipse.ui.handlers.RegistryToggleState:false"
id="org.eclipse.ui.commands.toggleState">
</state>
</command>
接下来我们给这三个command绑定handler,现在org.eclipse.ui.handlers扩展点下面建立三个handler,下面是其对应的xml内容:
<handler
class="cn.sunline.suncard.powerdesigner.handler.TableModelShowType_P"
commandId="sunline.suncard.powerdesigner.commands.onlyshowprimarykey">
</handler>
<handler
class="cn.sunline.suncard.powerdesigner.handler.TableModelShowType_PF"
commandId="sunline.suncard.powerdesigner.commands.showprimaryandforeign">
</handler>
<handler
class="cn.sunline.suncard.powerdesigner.handler.TableModelShowType_ALL"
commandId="sunline.suncard.powerdesigner.commands.showall">
</handler>
其中,我们建立了三个类,TableModelShowType_P用于处理只显示主键,TableModelShowType_PF用于处理显示主外键,TableModelShowType_ALL用于处理现实全部。最后会附上其中一个类的代码。
接下来就是在org.eclipse.ui.menus扩展点下建立menu节点,截图如下:
注意,这里的command节点需要在style的下拉列表中选择toggle风格!!
xml内容如下:
<menu
icon="icons/table_16.png"
label="%tablediagramshowtype">
<command
commandId="sunline.suncard.powerdesigner.commands.onlyshowprimarykey"
label="%onlyshowprimarykey"
style="toggle">
</command>
<command
commandId="sunline.suncard.powerdesigner.commands.showprimaryandforeign"
id="sunline.suncard.powerdesigner.commands.showprimaryandforeign"
label="%showprimaryandforeign"
name="%showprimaryandforegin"
style="toggle">
</command>
<command
commandId="sunline.suncard.powerdesigner.commands.showall"
label="%showall"
name="%showall"
style="toggle">
</command>
</menu>
接下来,我们可以看见效果了,运行系统后发现,这三个菜单都可以打勾,但根据我们的需求,只希望一个被大勾,这怎么办呢?于是,我们可以通过handler中的代码来控制,我们来看看其中一个handler——TableModelShowType_ALL(全部显示)中的代码内容:
public class TableModelShowType_ALL extends AbstractHandler{
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
Command allShowCommand = event.getCommand();
State allState = allShowCommand.getState(RegistryToggleState.STATE_ID);
allState.setValue(true);
// 因为全部显示菜单被勾选了,其他两个菜单需要设置为不勾选
ICommandService service = (ICommandService) PlatformUI.getWorkbench()
.getService(ICommandService.class);
// 设置“只显示主键”菜单为不勾选状态
Command pCommand = service.getCommand("sunline.suncard.powerdesigner.commands.onlyshowprimarykey");
State pState = pCommand.getState(RegistryToggleState.STATE_ID);
pState.setValue(false);
// 设置“显示主外键”菜单为不勾选状态
Command pfCommand = service.getCommand("sunline.suncard.powerdesigner.commands.showprimaryandforeign");
State pfState = pfCommand.getState(RegistryToggleState.STATE_ID);
pfState.setValue(false);
// 刷新菜单状态
service.refreshElements(allShowCommand.getId(), null);
service.refreshElements(pCommand.getId(), null);
service.refreshElements(pfCommand.getId(), null);
return null;
}
}
注意, allState.setValue(true); 保证了如果当前是“全部显示”菜单被勾选,用于如果继续点击“全部显示” 菜单,该菜单还是会被勾选,而不是被取消勾选。而且,如果这三个command下面的state节点的id不是org.eclipse.ui.commands.toggleState,假如“只显示主键”的command节点下的state节点的id是org.eclipse.ui.commands.toggleState_showall,则State pfState = pfCommand.getState(RegistryToggleState.STATE_ID); 需要改成State pfState = pfCommand.getState("org.eclipse.ui.commands.toggleState_showall");,否则获取的pfState将为空。但即使这样,你会发现行为达不到预期的效果,就是说“只显示主键”菜单依然我行我素,单击它它会勾选,再次单击它它会取消勾选,就是说pState.setValue(false);没有效果。调试过程中看下源代码会发现原因:
在HandlerProxy类中,有一个handleStateChange方法,该方法来自IStateListener接口,该接口也只有这一个方法,主要用来当菜单的状态改变时,需要旧的状态值需要用某一个值来更新。在HandlerProxy类中,实现代码如下
public void handleStateChange(State state, Object oldValue) {
if (state.getId().equals(RegistryToggleState.STATE_ID)) {
checkedState = state;
refreshElements();
} else if (state.getId().equals(RadioState.STATE_ID)) {
radioState = state;
refreshElements();
}
if (handler instanceof IStateListener) {
((IStateListener) handler).handleStateChange(state, oldValue);
}
}
因为你的state的id不是RegistryToggleState.STATE_ID,hander绑定的类也没有实现IStateListener接口,所以这个方法里面的代码根本没被执行,菜单的值和状态也没有得到更新。