NC65客开避坑指南:新增按钮时,你的XML和Java代码真的配好了吗?
·
NC65客开实战:按钮配置的七大隐形陷阱与深度调试技巧
在NC65的二次开发中,按钮配置看似简单却暗藏玄机。许多开发者按照教程一步步操作后,却发现按钮要么神秘消失,要么点击无反应。本文将带你深入NC65按钮渲染的核心机制,揭示那些官方文档从未提及的配置陷阱。
1. XML配置的三大死亡陷阱
1.1 actionContainer与actionType的致命组合
<bean class="nc.ui.pubapp.plugin.action.InsertActionInfo">
<property name="actionContainer" ref="actionsOfCard" />
<property name="actionType" value="notedit" />
</bean>
这个看似简单的配置片段中隐藏着两个关键参数:
- actionContainer :决定按钮出现在卡片(actionsOfCard)还是列表(actionsOfList)视图
- actionType :控制按钮在编辑(edit)或非编辑(notedit)状态下的显示
注意:当actionType设为"edit"时,必须确保单据处于可编辑状态,否则按钮不会渲染。这是最常见的配置失误之一。
1.2 bean引用路径的幽灵错误
<bean id="NonProdShipAction" class="nc.ui.so.m30.billui.action.NonProdShipAction">
<property name="model" ref="manageAppModel" />
<property name="editor" ref="billFormEditor" />
</bean>
常见错误对照表:
| 错误类型 | 正确写法 | 错误表现 |
|---|---|---|
| 类路径错误 | nc.ui.so.m30.billui.action.NonProdShipAction | 按钮完全不显示 |
| ref引用错误 | ref="manageAppModel" | 按钮显示但点击报空指针 |
| 属性缺失 | 必须包含model和editor | 按钮功能异常 |
1.3 位置参数的隐形规则
<property name="pos" value="before" />
<property name="target" ref="printActionGroup" />
pos参数有严格限制:
- 只能使用"before"或"after",大小写敏感
- target引用的必须是已存在的actionGroup
- 组名必须与BeanConfigFilePath中的定义完全一致
2. Java代码的四大暗礁
2.1 类继承的强制要求
public class NonProdShipAction extends NCAction {
// 必须继承NCAction
}
忘记继承NCAction是导致按钮点击无效的元凶之一。 此外还需注意:
- 必须实现doAction方法
- 建议重写isActionEnable控制按钮状态
- 保持无参构造函数
2.2 路径一致性的致命细节
Java类全路径必须与XML中的class属性 完全一致 ,包括:
- 包名大小写
- 类名拼写
- 所在模块路径
提示:使用Eclipse的"Copy Qualified Name"功能可避免手动输入错误。
2.3 属性注入的隐藏要求
private BillForm editor;
private AbstractAppModel model;
// 必须提供setter方法
public void setEditor(BillForm editor) {
this.editor = editor;
}
Spring注入的三大铁律:
- 属性必须有对应的setter方法
- setter方法命名必须符合JavaBean规范
- 基本类型属性需要默认值
2.4 事件处理的常见陷阱
@Override
public void doAction(ActionEvent event) {
// 错误示例:直接修改UI不检查线程
editor.setVisible(false);
// 正确做法
SwingUtilities.invokeLater(() -> {
MessageDialog.showHintDlg(editor, "提示", "操作成功");
});
}
3. 调试技巧:当按钮消失时该怎么办
3.1 日志分析的黄金法则
在log4j.properties中添加:
log4j.logger.nc.ui.pubapp.plugin.action=DEBUG
log4j.logger.nc.ui.uif2.actions=DEBUG
关键日志信息解读:
- "Registering action..." → 按钮已加载
- "Skipping action due to..." → 条件不满足
- "Cannot find reference..." → 引用错误
3.2 运行时诊断的三把利剑
- Bean检查工具 :
UIF2BeanFactory factory = BillUIUtil.getBeanFactory(editor);
Object bean = factory.getBean("NonProdShipAction");
- 属性追踪技巧 :
System.out.println(editor.getModel().getUiState());
- 事件监听诊断 :
Arrays.stream(editor.getActionListeners())
.forEach(l -> System.out.println(l.getClass()));
4. 高级配置:动态按钮控制
4.1 条件显示的高级技巧
@Override
protected boolean isActionEnable() {
// 根据业务状态动态控制
return model.getUiState() == UIState.NOT_EDIT
&& hasPermission("BTN_PERMISSION");
}
4.2 动态注入的实战方案
public void registerDynamicAction() {
InsertActionInfo info = new InsertActionInfo();
info.setActionContainer("actionsOfCard");
// ...其他配置
BillUIUtil.getBeanFactory(editor)
.registerSingleton("dynamicAction", info);
}
4.3 按钮组扩展的黑科技
<!-- 在标准按钮组旁添加自定义组 -->
<bean id="customActionGroup" class="javax.swing.ActionGroup">
<property name="actions">
<list>
<ref bean="action1" />
<ref bean="action2" />
</list>
</property>
</bean>
5. 性能优化:按钮加载的隐藏成本
5.1 懒加载的最佳实践
@Lazy
@Bean
public NonProdShipAction shipAction() {
return new NonProdShipAction();
}
5.2 资源清理的注意事项
@Override
public void dispose() {
model.removeAppEventListener(this);
super.dispose();
}
6. 跨版本兼容方案
6.1 NC65与NCCloud的差异处理
String version = System.getProperty("nc.version");
if (version.startsWith("6.5")) {
// NC65特有逻辑
} else {
// NCCloud适配代码
}
6.2 补丁影响的应对策略
创建版本兼容层:
public interface ActionCompat {
void registerAction(InsertActionInfo info);
}
public class NC65ActionImpl implements ActionCompat {
// NC65具体实现
}
7. 实战案例:运单按钮完整实现
7.1 完整XML配置
<beans>
<!-- 主按钮定义 -->
<bean id="NonProdShipAction"
class="nc.ui.so.m30.billui.action.NonProdShipAction">
<property name="code" value="SHIP_ACTION" />
</bean>
<!-- 卡片视图注册 -->
<bean class="nc.ui.pubapp.plugin.action.InsertActionInfo">
<property name="pos" value="after" />
<property name="target" ref="exportActionGroup" />
</bean>
</beans>
7.2 完整Java实现
public class NonProdShipAction extends NCAction {
@Override
public void doAction(ActionEvent e) {
new ShipInfoDialog(editor).show();
}
private class ShipInfoDialog extends JDialog {
// 自定义对话框实现
}
}
在项目压力测试阶段,我们发现当单据包含超过20个自定义按钮时,界面加载时间会显著增加。通过分析,最终定位到是多个按钮重复初始化相同的资源导致的。解决方案是为共享资源创建静态缓存:
private static final Map<String, ImageIcon> ICON_CACHE =
Collections.synchronizedMap(new HashMap<>());
private ImageIcon loadIcon(String path) {
return ICON_CACHE.computeIfAbsent(path, p ->
new ImageIcon(getClass().getResource(p)));
}
更多推荐


所有评论(0)