RAC 胖客户端定制开发:菜单、工具栏与 UI 扩展实战

Teamcenter Rich Client(RAC)是基于 Eclipse RCP(Rich Client Platform)构建的胖客户端。相比 Web 客户端(AWC),RAC 提供了更强大的功能定制能力和更丰富的交互体验。

2

RAC 胖客户端定制开发:菜单、工具栏与 UI 扩展实战

本文参考 IMA Teamcenter 知识库中的《富客户端订制程序员指南》《TC9 客户端开发培训》《RCP 平台技术》等资料,结合实战经验编写。

Teamcenter Rich Client(RAC)是基于 Eclipse RCP(Rich Client Platform)构建的胖客户端。相比 Web 客户端(AWC),RAC 提供了更强大的功能定制能力和更丰富的交互体验。很多企业选择 RAC 作为主力客户端,正是因为它支持深度的 UI 定制。

本文将从菜单扩展、工具栏定制、视图开发、对话框扩展等维度,系统讲解 RAC 胖客户端的定制开发实战。

一、RAC 客户端架构

1.1 Eclipse RCP 基础

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Eclipse RCP 架构:
├── Workbench(工作台)
│   ├── Perspective(透视图)
│   │   ├── View(视图)
│   │   └── Editor(编辑器)
│   ├── Menu(菜单)
│   ├── Toolbar(工具栏)
│   └── Status Line(状态栏)
└── Plugin(插件)
    ├── Extension(扩展点)
    └── Extension Point(扩展点定义)

1.2 Teamcenter RAC 结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Teamcenter RAC 安装目录:
├── tc_root/
│   ├── bin/
│   │   └── rac_client/
│   │       ├── eclipse/          # Eclipse 运行时
│   │       ├── plugins/          # 插件目录
│   │       ├── features/         # 特性目录
│   │       ├── configuration/    # 配置文件
│   │       └── dropins/          # 自定义插件(推荐部署位置)
│   ├── portal/                   # Web 门户
│   └── tcdata/                   # TC 数据

1.3 开发环境搭建

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
开发工具:
├── Eclipse IDE(推荐 4.26+)
├── Teamcenter RAC SDK
├── BMIDE(业务建模)
└── JDK 11+

配置步骤:
1. 安装 Eclipse IDE for RCP and RAP Developers
2. 导入 Teamcenter RAC 插件源码
3. 配置 Target Platform 指向 RAC 安装目录
4. 创建新的 Plugin Project
5. 添加 Teamcenter 依赖

二、菜单扩展

2.1 菜单扩展原理

Teamcenter RAC 使用 Eclipse 的 org.eclipse.ui.menus 扩展点来注册菜单项:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<extension point="org.eclipse.ui.menus">
  <menuContribution locationURI="menu:com.teamcenter.rac.main.menu?after=additions">
    <menu id="com.mycompany.menu" label="我的工具">
      <command commandId="com.mycompany.command.openTool"
               label="打开工具"
               style="push">
      </command>
    </menu>
  </menuContribution>
</extension>

2.2 实战:添加自定义菜单

Step 1:创建 Plugin 项目

1
2
3
4
5
Eclipse → File → New → Plug-in Project
→ Name: com.mycompany.rac.extension
→ Target: Eclipse 4.x
→ Options: Generate an activator
→ Finish

Step 2:定义命令(Command)

1
2
3
4
5
6
7
<!-- plugin.xml -->
<extension point="org.eclipse.ui.commands">
  <command id="com.mycompany.command.openCustomDialog"
           name="打开自定义对话框"
           categoryId="com.teamcenter.rac.commands.category">
  </command>
</extension>

Step 3:定义 Handler

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.mycompany.rac.handlers;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.handlers.HandlerUtil;

public class OpenCustomDialogHandler extends AbstractHandler {

    @Override
    public Object execute(ExecutionEvent event) throws ExecutionException {
        Shell shell = HandlerUtil.getActiveWorkbenchWindow(event)
                .getShell();

        MessageDialog.openInformation(
            shell,
            "自定义对话框",
            "Hello from Teamcenter RAC Extension!"
        );

        return null;
    }
}

Step 4:注册 Handler

1
2
3
4
5
<extension point="org.eclipse.ui.handlers">
  <handler commandId="com.mycompany.command.openCustomDialog"
           class="com.mycompany.rac.handlers.OpenCustomDialogHandler">
  </handler>
</extension>

Step 5:添加到菜单

1
2
3
4
5
6
7
8
<extension point="org.eclipse.ui.menus">
  <menuContribution locationURI="menu:com.teamcenter.rac.main.menu?after=additions">
    <command commandId="com.mycompany.command.openCustomDialog"
             label="我的工具"
             style="push">
    </command>
  </menuContribution>
</extension>

2.3 上下文菜单扩展

上下文菜单(右键菜单)的添加方式略有不同:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<extension point="org.eclipse.ui.popupMenus">
  <objectContribution
      objectClass="com.teamcenter.rac.kernel.TCComponentItem"
      id="com.mycompany.itemContribution">
    <menu id="com.mycompany.itemMenu"
          label="自定义操作"
          path="additions">
      <separator name="group1"/>
    </menu>
    <action
        id="com.mycompany.itemAction"
        label="查看自定义信息"
        class="com.mycompany.rac.actions.ItemCustomAction"
        enablesFor="1"
        menubarPath="com.mycompany.itemMenu/group1">
    </action>
  </objectContribution>
</extension>

Action 实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.mycompany.rac.actions;

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;

import com.teamcenter.rac.kernel.TCComponentItem;
import com.teamcenter.rac.util.Registry;

public class ItemCustomAction implements IObjectActionDelegate {

    private IStructuredSelection selection;

    @Override
    public void setActivePart(IAction action, IWorkbenchPart targetPart) {
    }

    @Override
    public void selectionChanged(IAction action, ISelection selection) {
        if (selection instanceof IStructuredSelection) {
            this.selection = (IStructuredSelection) selection;
        }
    }

    @Override
    public void run(IAction action) {
        if (selection != null && !selection.isEmpty()) {
            Object obj = selection.getFirstElement();
            if (obj instanceof TCComponentItem) {
                TCComponentItem item = (TCComponentItem) obj;
                String itemId = item.getProperty("item_id");
                String itemName = item.getProperty("object_string");

                // 执行自定义操作
                System.out.println("Selected item: " + itemId + " - " + itemName);
            }
        }
    }
}

三、工具栏定制

3.1 添加工具栏按钮

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<extension point="org.eclipse.ui.menus">
  <menuContribution locationURI="toolbar:com.teamcenter.rac.main.toolbar?after=additions">
    <command commandId="com.mycompany.command.openCustomDialog"
             label="我的工具"
             icon="icons/tool.png"
             style="push"
             tooltip="打开自定义工具">
    </command>
  </menuContribution>
</extension>

3.2 工具栏按钮状态管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class ToggleToolHandler extends AbstractHandler {

    private boolean isActive = false;

    @Override
    public Object execute(ExecutionEvent event) throws ExecutionException {
        isActive = !isActive;

        // 更新按钮状态
        ICommandService cmdService = (ICommandService)
            HandlerUtil.getActiveWorkbenchWindow(event)
                .getService(ICommandService.class);
        Command cmd = cmdService.getCommand("com.mycompany.command.toggleTool");
        State state = cmd.getState("org.eclipse.ui.handlers.RadioState");
        if (state != null) {
            state.setValue(isActive ? "true" : "false");
        }

        return null;
    }
}

3.3 动态工具栏

根据当前上下文动态显示/隐藏工具栏按钮:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<extension point="org.eclipse.ui.menus">
  <menuContribution locationURI="toolbar:com.teamcenter.rac.main.toolbar">
    <command commandId="com.mycompany.command.bomTool"
             label="BOM 工具"
             style="push">
      <visibleWhen>
        <with variable="selection">
          <iterate>
            <instanceof value="com.teamcenter.rac.kernel.TCComponentBOMLine"/>
          </iterate>
        </with>
      </visibleWhen>
    </command>
  </menuContribution>
</extension>

四、视图(View)开发

4.1 创建自定义视图

1
2
3
4
5
6
7
<extension point="org.eclipse.ui.views">
  <view id="com.mycompany.rac.view.customView"
        name="自定义视图"
        class="com.mycompany.rac.views.CustomView"
        category="com.teamcenter.rac.views.category">
  </view>
</extension>

4.2 视图实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.mycompany.rac.views;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.part.ViewPart;

import com.teamcenter.rac.kernel.TCComponent;
import com.teamcenter.rac.kernel.TCException;
import com.teamcenter.rac.kernel.TCSession;
import com.teamcenter.rac.ui.UITools;

public class CustomView extends ViewPart {

    private Table table;

    @Override
    public void createPartControl(Composite parent) {
        // 创建表格
        table = new Table(parent, SWT.BORDER | SWT.FULL_SELECTION);
        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        // 添加列
        TableColumn col1 = new TableColumn(table, SWT.LEFT);
        col1.setText("零部件编号");
        col1.setWidth(150);

        TableColumn col2 = new TableColumn(table, SWT.LEFT);
        col2.setText("名称");
        col2.setWidth(200);

        TableColumn col3 = new TableColumn(table, SWT.LEFT);
        col3.setText("版本");
        col3.setWidth(80);

        // 加载数据
        loadData();
    }

    private void loadData() {
        try {
            TCSession session = (TCSession) UITools.getDefaultSession();
            // 查询数据并填充表格
            TCComponent[] items = session.find("Item", "item_id", "*");
            for (TCComponent item : items) {
                TableItem row = new TableItem(table, SWT.NONE);
                row.setText(new String[]{
                    item.getProperty("item_id"),
                    item.getProperty("object_string"),
                    item.getProperty("object_type")
                });
            }
        } catch (TCException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setFocus() {
        table.setFocus();
    }
}

4.3 视图与透视图集成

1
2
3
4
5
6
7
8
9
<!-- 将视图添加到 Teamcenter 透视图中 -->
<extension point="org.eclipse.ui.perspectiveExtensions">
  <perspectiveExtension targetID="com.teamcenter.rac.perspective">
    <view id="com.mycompany.rac.view.customView"
          relationship="right"
          relative="com.teamcenter.rac.view.navigator">
    </view>
  </perspectiveExtension>
</extension>

五、对话框(Dialog)开发

5.1 简单对话框

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class SimpleInputDialog extends TitleAreaDialog {

    private Text inputText;
    private String inputValue;

    public SimpleInputDialog(Shell parentShell) {
        super(parentShell);
    }

    @Override
    protected Control createDialogArea(Composite parent) {
        Composite area = (Composite) super.createDialogArea(parent);
        Composite container = new Composite(area, SWT.NONE);
        container.setLayout(new GridLayout(2, false));

        new Label(container, SWT.NONE).setText("请输入:");
        inputText = new Text(container, SWT.BORDER);
        inputText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        setTitle("自定义输入对话框");
        setMessage("请输入需要的参数");

        return area;
    }

    @Override
    protected void okPressed() {
        inputValue = inputText.getText();
        super.okPressed();
    }

    public String getInputValue() {
        return inputValue;
    }
}

5.2 使用对话框

1
2
3
4
5
6
SimpleInputDialog dialog = new SimpleInputDialog(shell);
if (dialog.open() == Window.OK) {
    String input = dialog.getInputValue();
    // 处理输入
    System.out.println("用户输入: " + input);
}

六、属性页(Property Page)扩展

6.1 添加自定义属性页

1
2
3
4
5
6
7
<extension point="org.eclipse.ui.propertyPages">
  <page id="com.mycompany.rac.propPage.itemCustom"
        name="自定义信息"
        class="com.mycompany.rac.propPages.ItemCustomPropPage"
        objectClass="com.teamcenter.rac.kernel.TCComponentItem">
  </page>
</extension>

6.2 属性页实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.mycompany.rac.propPages;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.ui.IWorkbenchPropertyPage;
import org.eclipse.ui.dialogs.PropertyPage;

import com.teamcenter.rac.kernel.TCComponentItem;

public class ItemCustomPropPage extends PropertyPage
        implements IWorkbenchPropertyPage {

    @Override
    protected Control createContents(Composite parent) {
        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayout(new GridLayout(2, false));

        TCComponentItem item = (TCComponentItem) getElement().getAdapter(
                TCComponentItem.class);

        try {
            // 添加自定义属性显示
            new Label(composite, SWT.NONE).setText("自定义编号:");
            Text customId = new Text(composite, SWT.READ_ONLY);
            customId.setText(item.getProperty("custom_id"));
            customId.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

            new Label(composite, SWT.NONE).setText("自定义描述:");
            Text customDesc = new Text(composite, SWT.READ_ONLY);
            customDesc.setText(item.getProperty("custom_desc"));
            customDesc.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

        } catch (Exception e) {
            e.printStackTrace();
        }

        return composite;
    }
}

七、部署与调试

7.1 部署方式

方式一:dropins 目录(推荐)

1
2
3
4
5
将编译好的插件 JAR 放入:
rac_client/dropins/com.mycompany.rac.extension/
├── plugins/
│   └── com.mycompany.rac.extension_1.0.0.jar
└── eclipsec.exe (Windows) / eclipse (Linux)

方式二:features 目录

1
2
3
4
创建 Feature 项目
→ 导出为 JAR
→ 放入 rac_client/features/
→ 更新 rac_client/configuration/config.ini

7.2 调试方法

启动 RAC 调试模式

1
2
3
4
5
# Windows
eclipsec.exe -consoleLog -debug -clean

# Linux
./eclipse -consoleLog -debug -clean

查看日志

1
2
3
4
5
6
7
日志文件位置:
rac_client/configuration/.metadata/.log

常见错误:
- Bundle 未激活:检查 MANIFEST.MF
- 扩展点未注册:检查 plugin.xml
- Class Not Found:检查依赖

7.3 打包发布

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
1. 使用 Eclipse 导出插件:
   File → Export → Deployable plugins and fragments
   → 选择目标插件
   → 导出为 JAR

2. 打包为更新站点(Update Site):
   File → Export → Deployable features
   → 选择特性
   → 生成更新站点

3. 使用 p2 安装:
   帮助 → 安装新软件
   → 添加更新站点 URL
   → 选择安装

八、最佳实践

8.1 开发规范

  1. 包命名:使用公司域名反写,如 com.mycompany.rac.xxx
  2. 版本管理:每次更新递增版本号
  3. 依赖最小化:只依赖必要的插件
  4. 异常处理:捕获并记录所有异常
  5. 用户反馈:操作完成后给出明确提示

8.2 性能优化

  1. 懒加载:视图数据按需加载
  2. 缓存机制:重复查询使用缓存
  3. 异步操作:耗时操作在后台线程执行
  4. UI 线程安全:使用 Display.asyncExec 更新 UI
1
2
3
4
5
6
7
8
9
// 后台线程查询数据
new Thread(() -> {
    TCComponent[] items = queryData();

    // 回到 UI 线程更新界面
    Display.getDefault().asyncExec(() -> {
        updateTable(items);
    });
}).start();

8.3 兼容性注意事项

  1. 版本兼容:测试不同 TC 版本的兼容性
  2. API 变更:关注 Teamcenter API 变更通知
  3. Eclipse 版本:确认 RCP 版本匹配
  4. Java 版本:使用 JDK 版本与 TC 一致

九、总结

RAC 胖客户端的定制开发能力是 Teamcenter 的重要优势。掌握以下技能,可以打造符合企业需求的高效客户端:

  1. 菜单扩展:添加自定义菜单和上下文菜单
  2. 工具栏定制:创建动态工具栏按钮
  3. 视图开发:开发自定义数据展示视图
  4. 对话框开发:创建交互式输入界面
  5. 属性页扩展:添加自定义属性显示
  6. 调试部署:掌握调试方法和部署流程

RAC 开发需要 Eclipse RCP 基础,建议先掌握 RCP 核心概念,再深入学习 Teamcenter 特有的扩展点和 API。

广告
广告位预留中 (728x90)