NetBeans IDE 5.0 Rich-Client Application 快速入门指南
反馈
本文档帮助您学习使用 NetBeans IDE 5.0 在 NetBeans Platform 上开发富客户端应用程序的基本知识。在 NetBeans Platform 上开发应用程序时,将在 NetBeans IDE 的核心上开发。属于 IDE 但与您的应用程序无关的所有模块都要排除,但应保留那些有用的模块。通过重用那些在 IDE 核心中随时可用的特性,您可以节省大量时间和资源。
本教程旨在让您尽快地上手。您将在 NetBeans Platform 上创建和安装简单的应用程序。该应用程序允许用户在屏幕上绘图并保存绘制的结果:
此初始版本还不是完全成熟的绘图应用程序,但它演示了一个在 NetBeans Platform 上创建应用程序的非常简单的例子。
注意,如果您想了解 NetBeans 插件模块,而不是富客户端应用程序,则NetBeans IDE 5.0 Plug-in Module 快速入门指南是一个更好的教程。
设置绘图应用程序
在这一部分,我们将创建应用程序的结构。首先需要创建一个表示您的应用程序的模块套件项目。该应用程序依赖库,因此要创建包含该库的 JAR 文件的库包装模块项目。最后创建包含您的代码的模块项目。
创建模块套件
模块套件等同于应用程序,它是一组共同协作以实现特定目标的模块。它也允许您指定自己的程序启动画面(标记)、应用程序名称,以及您想使用的 NetBeans 模块的类型和数量。还可以利用此类操作,如创建 ZIP 分发和构建 Java WebStart (JNLP) 应用程序,这些都是使您的应用程序能被其他用户使用的重要工具。
- 选择 File > New Project。在 Categories 下,选择 NetBeans Plug-in Modules。在 Projects 下,选择 Module Suite Project 并单击 Next。
- 在 Name and Location 面板上,在 Project Name 中键入 PaintApp。将 Project Location 更改为计算机上的任意目录。选定 Set as Main Project 复选框:
单击 Finish。
新的模块套件项目在 IDE 中打开。该项目在 Project 窗口中包含一个节点。此节点(Modules 节点)用于手动将模块项目和库包装模块项目添加到模块套件项目。使用 Module Project 向导或 Library Wrapper Module Project 向导时,您创建的模块可以自动添加到模块套件项目中。
创建库包装模块项目
库包装模块是一个其 JAR 文件不包含节点的模块——它只是一个指向库的指针。它可将库转换为 NetBeans 模块,所以对 NetBeans 类加载器系统的所有保护都适用于它——无需修改最初的 JAR 文件。然后您的应用程序可以依赖于该库,就好像该库是另一个 NetBeans 模块一样。并且,如果该库的新版本变得可用,则您可以分发它们,不需要分发包装库的单个 NetBeans Module (NBM) 文件之外的任何内容。
在 NetBeans Platform 上构建的好处之一是其用户界面基于 Swing,即 Java 的标准用户界面工具包。由于 Swing 已使用了很长时间,所以有许多 Swing 组件可以在您的应用程序中重用。在本教程中,可重用现有的颜色拾取器 JavaBean(可以在 contrib/coloreditor 下的 NetBeans CVS 中找到它的源代码)。JAR 文件称作 ColorChooser.jar。您可以在此处下载文件。将它保存在文件系统中的任意位置。执行以下操作创建 ColorChooser.jar 文件的库包装模块:
- 选择 File > New Project。在 Categories 下,选择 NetBeans Plug-in Modules。在 Projects 下,选择 Library Wrapper Module Project 并单击 Next。
- 在 Name and Location 面板中,在 Library 中浏览您要将 ColorChooser.jar 下载到的位置。
- 将 License 文本字段空出。如果您想打算分发完整的产品,则应包括外部库的许可证文件。
- 单击 Next,再单击 Next,然后单击 Finish。
创建模块项目
现在您需要一个模块来包含打算编写的实际代码。
- 选择 File > New Project。在 Categories 下,选择 NetBeans Plug-in Modules。在 Projects 下,选择 Module Project 并单击 Next。
- 在 Name and Location 面板中,在 Project Name 中键入 Paint。将 Project Location 更改为计算机上的任意目录。确保选择 Add to Module Suite 单选按钮,并确保在 Module Suite 下拉列表中选择 PaintApp 模块套件。选中 Set as Main Project 复选框。单击 Next。
- 在 Basic Module Configuration 面板中,将 Code Name Base 中的 yourorghere 改为 netbeans,于是全名就是 org.netbeans.paint。在 Module Display Name 中填入 Paint。空出本地化资源包和 XML 层的位置,以便将它们存储在具有名称 org.netbeans.paint 的包中。这些文件执行以下操作:
- 本地化资源包。 指定用于国际化的特定于语言的字符串。
- XML 层。 在 NetBeans 系统中注册菜单和工具栏之类的项。
单击 Finish。
IDE 创建 Paint 项目。该项目包含所有资源和项目元数据,如该项目的 Ant 构建脚本。该项目在 IDE 中打开。您可以在 Projects 窗口 (Ctrl-1) 中查看其逻辑结构,在 Files 窗口 (Ctrl-2) 中查看其文件结构。例如,Projects 窗口应该类似如下:
除本地化资源包和 XML 层之外,该项目还包括以下重要文件:
- 模块清单(Module Manifest)。 声明该项目是插件模块。此外,它设置一些特定于模块的设置,如 XML 层的位置、本地化资源包的位置和模块版本。
- 构建脚本。 提供一个您可以创建自己的 Ant 目标和重写在 nbproject/build-impl.xml 中指定的目标的位置。
- 项目元数据。 包含以下信息,如该项目类型、内容、平台、类路径、依赖性,以及 Ant 脚本中项目命令和目标之间的映射。
在学习本教程的过程中不需要修改任何这些文件。
指定模块项目的依存关系
您需要子类化几个属于 NetBeans API 的类。此外,该项目依赖 ColorChooser.jar 文件。所有 NetBeans API 都由插件模块实现,所以完成这两项任务仅仅意味着将一些插件模块添加插件模块列表,我们的插件模块运行时需要该列表。
- 在 Projects 窗口中,右键单击 Paint 项目节点并选择 Properties。在 Project Properties 对话框中单击 Libraries。
- 对于以下每个 API,单击“Add...”,然后开始键入想要子类化的类的名称。键入后,可以提供该类的 NetBeans API 的数目减少,并且只有可以提供该类的 NetBeans API 显示在 Module 列表中:
下表第一栏列出了您将在本教程中子类化的所有类。在每种情况下,开始键入类名称并观察 Module 列表减少的情况。使用下表中的第二栏从减少的 Module 列表中选出适当的 API(或者,在 ColorChooser 例子中,则选择库),然后单击 OK 以确认选择:
|
类
|
API
|
目的
|
| ColorChooser |
ColorChooser |
您创建的颜色拾取器组件的库包装模块 |
| DataObject |
数据系统 API |
包含 DataObject 类的 Netbeans 模块 |
| DialogDisplayer |
对话框 API |
这允许创建用户通知、对话框描述,并且允许显示它 |
| AbstractFileObject |
文件系统 API |
这提供以统一方式访问文件的常见 API |
| AbstractNode |
节点 API |
这充当在 NetBeans 中可视化对象的主要设置 |
| StatusDisplayer |
UI 实用工具 API |
用于编写主窗口中的状态栏的 StatusDisplayer 类 |
| WeakListeners |
实用工具 API |
这包含该 WeakListener 类 |
| TopComponent |
Window 系统 API |
这包含 TopComponent JPanel 类 |
- 单击 OK,退出 Project Properties 对话框。
- 在 Projects 窗口中,展开 Important Files 节点,双击 Project Metadata 节点,并注意查看您选择的 API 是否按模块依赖性进行了声明。
创建画布
下一步是创建用户可以在上面绘图的实际组件。这里,您可使用纯 Swing 组件——因此,我们跳过它实现的详细信息,并且只提供最终版本。您为其创建库包装模块颜色拾取器的 bean 用于此面板的源代码——运行完成的应用程序时,您将在编辑图像面板的工具栏中看到它。
- 在 Projects 窗口中,展开 Paint 节点,然后展开 Source Packages 节点,接着右键单击 org.netbeans.paint 节点。选择 New > Java Class。
- 输入 PaintCanvas 作为 Class Name。确保 Package 中列出了 org.netbeans.paint。单击 Finish。PaintCanvas.java 即在 Source Editor 中打开。
- 用此处的内容替换文件的默认内容。如果您将包命名为 org.netbeans.paint 之外的其他名称,则在 Source Editor 中改正包名称。
实现模块
现在可以编写第一个接触 NetBeans API 的类。它是一个 TopComponent 类。TopComponent 类只是一个 JPanel 类,NetBeans 的窗口操作系统知道如何与它对话——因此可以将它放入主窗口中包含选项卡的窗口内。
准备 TopComponent 类
- 在 Projects 窗口中,展开 Paint 节点,然后展开 Source Packages 节点,接着右键单击 org.netbeans.paint 节点。选择 New > Java Class。
- 输入 PaintTopComponent 作为 Class Name。确保 Package 中列出了 org.netbeans.paint。单击 Finish。PaintTopComponent.java 即在 Source Editor 中打开。
- 在接近文件顶部的位置,将类声明更改为如下:
public class PaintTopComponent extends TopComponent implements ActionListener, ChangeListener {
- 按下 Alt-Shift-F 以固定导入。IDE 会将必要的导入包声明置于文件顶部。
注意您刚输入的类声明下的红色波浪线。将光标放在该线上并注意左边的空白处出现的电灯泡。单击该电灯泡(或按下 Alt-Enter),如下所示:
选择 Implement all abstract methods。IDE 即可生成两个方法框架:actionPerformed() 和 stateChanged()。稍后您要在本教程中填充这些框架。
- 将以下三个参数声明添加到 PaintTopComponent 类的顶部,然后固定导入语句 (Alt-Shift-F)。
private PaintCanvas canvas = new PaintCanvas(); //The component the user draws on
private JComponent preview; //A component in the toolbar that shows the paintbrush size
private static int ct = 0; //A counter you use to provide names for new images
- 现在您需要实现两个样板方法。第一个方法告知窗口操作系统在关闭应用程序时忽略打开的窗口;第二个方法为组件的惟一字符串 ID 提供基本字符串。每个 TopComponent 都有一个在保存 TopComponent 时惟一的字符串 ID。将以下两个方法插入到 PaintTopComponent 类:
public int getPersistenceType() {
return PERSISTENCE_NEVER;
}
public String preferredID() {
return "Image";
}
初始化 TopComponent 类
- 填写构造方法(IDE 在靠近类的顶部为您创建的构造方法),然后固定导入语句 (Alt-Shift-F):
public PaintTopComponent() {
initComponents();
String displayName = NbBundle.getMessage(
PaintTopComponent.class,
"UnsavedImageNameFormat",
new Object[] { new Integer(ct++) }
);
setDisplayName(displayName);
}
这里的代码相当简单。首先调用的是您尚未编写的方法 initComponents(),它将向您的 TopComponent 添加一个工具栏和 PaintCanvas。因为您尚未编写该方法,所以在它下面出现红色波浪线。与以前一样,单击电灯泡(或按下 Alt-Enter)并接受建议:
这样就生成了 initComponents() 方法框架。
- 在 Projects 窗口中展开 org.netbeans.paint 包。双击 Bundle.properties 文件在 Source Editor 中打开它。将以下行添加到文件末尾:
UnsavedImageNameFormat=Image {0}
确保在继续之前保存文件。
填写 Skeleton 方法
- initComponents() 方法在用户面板中安装组件,所以用户可以与其交互。您已在前一部分生成它的框架方法。填写如下:
private void initComponents() {
setLayout(new BorderLayout());
JToolBar bar = new JToolBar();
ColorChooser fg = new ColorChooser();
preview = canvas.createBrushSizeView();
//Now build our toolbar:
//Make sure components don't get squished:
Dimension min = new Dimension(32, 32);
preview.setMaximumSize(min);
fg.setPreferredSize(new Dimension(16, 16));
fg.setMinimumSize(min);
fg.setMaximumSize(min);
JButton clear = new JButton(
NbBundle.getMessage(PaintTopComponent.class, "LBL_Clear"));
JLabel fore = new JLabel(
NbBundle.getMessage(PaintTopComponent.class, "LBL_Foreground"));
fg.addActionListener(this);
clear.addActionListener(this);
JSlider js = new JSlider();
js.setMinimum(1);
js.setMaximum(24);
js.setValue(canvas.getDiam());
js.addChangeListener(this);
fg.setColor(canvas.getColor());
bar.add(clear);
bar.add(fore);
bar.add(fg);
JLabel bsize = new JLabel(
NbBundle.getMessage(PaintTopComponent.class, "LBL_BrushSize"));
bar.add(bsize);
bar.add(js);
bar.add(preview);
JLabel spacer = new JLabel(" "); //Just a spacer so the brush preview
//isn't stretched to the end of the
//toolbar
spacer.setPreferredSize(new Dimension(400, 24));
bar.add(spacer);
//And install the toolbar and the painting component:
add(bar, BorderLayout.NORTH);
add(canvas, BorderLayout.CENTER);
}
- 按下 Alt-Shift-F 以生成所需的导入语句。
- 填写您生成的其他两个方法。它们用于侦听 PaintTopComponent 类:
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
canvas.clear();
} else if (e.getSource() instanceof ColorChooser) {
ColorChooser cc = (ColorChooser) e.getSource();
canvas.setPaint (cc.getColor());
}
preview.paintImmediately(0, 0, preview.getWidth(), preview.getHeight());
}
public void stateChanged(ChangeEvent e) {
JSlider js = (JSlider) e.getSource();
canvas.setDiam (js.getValue());
preview.paintImmediately(0, 0, preview.getWidth(), preview.getHeight());
}
- 在 Bundle.properties 文件中,将以下键-值添加到文件的末尾:
LBL_Clear = Clear
LBL_Foreground = Foreground
LBL_BrushSize = Brush Size
确保在继续之前保存文件。
将图像保存到磁盘
- 将以下代码插入到 PaintTopComponent 类:
public void save() throws IOException {
if (getDisplayName().endsWith(".png")) {
doSave(new File(getDisplayName()));
} else {
saveAs();
}
}
public void saveAs() throws IOException {
JFileChooser ch = new JFileChooser();
if (ch.showSaveDialog(this) == JFileChooser.APPROVE_OPTION && ch.getSelectedFile() != null) {
File f = ch.getSelectedFile();
if (!f.getPath().endsWith(".png")) {
f = new File(f.getPath() + ".png");
}
if (!f.exists()) {
if (!f.createNewFile()) {
String failMsg = NbBundle.getMessage(
PaintTopComponent.class,
"MSG_SaveFailed", new Object[] { f.getPath() }
);
JOptionPane.showMessageDialog(this, failMsg);
return;
}
} else {
String overwriteMsg = NbBundle.getMessage(
PaintTopComponent.class,
"MSG_Overwrite", new Object[] { f.getPath() }
);
if (JOptionPane.showConfirmDialog(this, overwriteMsg)
!= JOptionPane.OK_OPTION) {
return;
}
}
doSave(f);
}
}
private void doSave(File f) throws IOException {
BufferedImage img = canvas.getImage();
ImageIO.write(img, "png", f);
String statusMsg = NbBundle.getMessage(PaintTopComponent.class,
"MSG_Saved", new Object[] { f.getPath() });
StatusDisplayer.getDefault().setStatusText(statusMsg);
setDisplayName(f.getName());
}
- 将以下代码添加到 Bundle.properties 文件:
MSG_SaveFailed = Could not write to file {0}
MSG_Overwrite = {0} exists. Overwrite?
MSG_Saved = Saved image to {0}
确保在继续之前保存文件。
- 单击 Alt-Shift-F 以固定导入语句。
创建菜单项
使用 NetBeans 插件模块文件模板来建立该模块的功能的基础。使用文件模板时,IDE 将注册您在 layer.xml 文件中创建的项。使用向导创建文件模板后,可以使用 NetBeans API 继续开发该模块。
定义新的画布动作
- 在 Projects 窗口中,右键单击该项目节点,并选择 New > File/Folder。在 New File 向导中,选择 Categories 下的 NetBeans Module Development 和 File Types 下的 Action。单击 Next。
- 在 Action Type 面板中,接受默认设置。单击 Next。
- 在 GUI Registration 面板中,选择 Global Menu Item 并选择 Global Toolbar Button。设置以下值:
- 类别: Edit
- 菜单: File
- 位置: <separator> - HERE - Open Project...
- 工具栏: File
- 位置: HERE - New File
注意: 在什么位置放置动作并不重要,只要它在 File 菜单和 File 工具栏中即可。
在 Global Menu Item 部分选择 Separator Before。
现在应该看到下图:
单击 Next。
- 在 Name, Icon, and Location 面板中,在 Class Name 中键入 NewCanvasAction,并在 Display Name 中键入 New Canvas。
在 Icon 中,粘贴此图标(在这里右键单击它,然后将它保存在 org.netbeans.paint 文件夹中):
- 单击 Finish。
IDE 在 org.netbeans.paint 中创建 NewCanvasAction.java 并在 Source Editor 中打开它。这是您应该看到的(单击该链接可以看到相关的 NetBeans API Javadoc):
package org.netbeans.paint;
import org.openide.util.HelpCtx;
import org.openide.util.actions.CallableSystemAction;
public final class NewCanvasAction extends CallableSystemAction {
public void performAction() {
// TODO implement action body
}
public String getName() {
return NbBundle.getMessage(NewCanvasAction.class, "CTL_NewCanvasAction");
}
protected String iconResource() {
return "org/netbeans/paint/newCanvas.gif";
}
public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}
protected boolean asynchronous() {
return false;
}
}
正如在 GUI Registration 面板中指定的那样,该 IDE 将在 layer.xml 文件中作为菜单项和工具栏按钮注册 action 类。
- 在 Source Editor 中,打开 NewCanvasAction.java 并填写 performAction() 方法,如下所示:
public void performAction() {
PaintTopComponent tc = new PaintTopComponent();
tc.open();
tc.requestActive();
}
此操作只创建我们的图像编辑组件的新实例,打开它,于是它出现在主窗口中,并且通过向它发送键盘焦点和选择其选项卡来激活它。
定义保存动作
- 在 Projects 窗口中,右键单击该项目节点,并选择 New > File/Folder。在 New File 向导中,选择 Categories 下的 NetBeans Module Development 和 File Types 下的 Action。单击 Next。
- 在 Action Type 面板中,接受默认设置。单击 Next。
- 在 GUI Registration 面板中,选择 Global Menu Item 并选择 Global Toolbar Button。设置以下值:
- 类别: Edit
- 菜单: File
- 位置: <instance of NewCanvasAction> - HERE - Print to HTML...
- 工具栏: File
- 位置: <instance of NewCanvasAction> - HERE - New File
注意: 在什么位置放置动作并不重要,只要它在 File 菜单和 File 工具栏中即可。
在 Global Menu Item 部分选择 Separator After。
单击 Next。
- 在 Name, Icon, and Location 面板中,在 Class Name 中键入 SaveCanvasAction,并在 Display Name 中键入 Save Canvas。
在 Icon 中,粘贴此图标(在这里右键单击它,然后将它保存在 org.netbeans.paint 文件夹中):
- 单击 Finish。
IDE 在 org.netbeans.paint 中创建 SaveCanvasAction.java 并在 Source Editor 中打开它。
- 在 Source Editor 中,打开 SaveCanvasAction.java 并填写 performAction() 方法,如下所示:
public void performAction() {
TopComponent tc = TopComponent.getRegistry().getActivated();
if (tc instanceof PaintTopComponent) {
try {
((PaintTopComponent) tc).saveAs();
} catch (IOException ioe) {
ErrorManager.getDefault().notify (ioe);
}
} else {
//Theoretically the active component could have changed
//between the time the menu item or toolbar button was
//pressed and when the action was invoked. Not likely,
//but theoretically possible
Toolkit.getDefaultToolkit().beep();
}
}
按下 Alt-Shift-F 以生成所需的 import 语句:
- 通过修改类声明添加属性更改侦听器:
public final class SaveCanvasAction extends CallableSystemAction implements PropertyChangeListener {
红色波浪线再次出现。按下 Alt-Enter 调出电灯泡并选择建议:
红色波浪线再次出现。重复前边的过程并接受建议:
填写生成的 propertyChange() 方法如下:
public void propertyChange(PropertyChangeEvent evt) {
if (TopComponent.Registry.PROP_ACTIVATED.equals(evt.getPropertyName())){
updateEnablement();
}
}
接下来定义 updateEnablement() 方法:
private void updateEnablement() {
setEnabled(TopComponent.getRegistry().getActivated()
instanceof PaintTopComponent);
}
最后,定义构造方法:
public SaveCanvasAction() {
TopComponent.getRegistry().addPropertyChangeListener (
WeakListeners.propertyChange(this,
TopComponent.getRegistry()));
updateEnablement();
}
有意义的主代码部分是添加属性更改侦听器。TopComponent.Registry 是系统中所有打开的 TopComponents(所有打开的选项卡)的注册表。我们想做的是侦听它的更改,根据焦点所在来启用或禁用动作。
注意,您可以调用 WeakListeners.propertyChange(),不用直接连接属性更改侦听器。此操作用于生成一个弱引用您的 action 的属性更改侦听器。实际上,只要应用程序打开,您的动作就是活动的。如果您连接了一个侦听器并且没有代码将它分开,则使用弱侦听器是一个好的做法。否则,您将会出现内存泄漏——您的动作可能无法进行垃圾收集,因为注册表在其侦听器列表中保持了对它的引用。
下面是现在应该在 Projects 窗口中看到的内容:
您现在有了一个工作模块!在 Projects 窗口中右键单击 PaintApp 节点,然后选择 Run。NetBeans IDE 的副本将与您安装的模块一起出现。
结束语
当然,您想要创建应用程序,而不是 IDE——所以您可以执行以下最后几个步骤。首先为应用程序创建一个启动屏幕(splash screen),然后删除不必要的模块,并在最后创建一个 ZIP 分发和一个 JNLP 应用程序。
进行标记
- 运行 PaintApp 项目。应用程序启动后,将主屏幕调得相当小,并拉出一个启动屏幕。使用 Save 按钮保存程序启动画面。
- 在最初的项目中,右键单击 PaintApp 节点,选择 Properties,然后单击 Project Properties 对话框中的 Application。
- 选择 Create Standalone Application,然后单击 Exclude。执行此操作时,从应用程序中删除与 IDE 相关的模块。例如,如果想让您的应用程序包含提供 IDE 及其编辑器功能的库,则改为单击 Skip。
- 在 Branding Name 中键入 paintit。此操作设置 IDE 为 ZIP 分发创建的启动程序的名称。
- 在 Application Title 中键入 Paint Application。此操作设置在新应用程序的标题栏中显示的名称。
- 单击 Splash Screen。
- 浏览您保存的 Splash Screen。如果您没有,则可以使用这一个。单击 OK 以将它连接到您的项目:
- 单击 Libraries,展开 platform6 节点。这是包含将与您的 Paint Application 绑定的模块的惟一集群。其中包括已检查的模块,不包括未经检查的模块。注意到许多模块已被删除。有一个模块需要手动删除:Core UI。现在就做,取消对它的选定。
现在,在该模块项目的 layer.xml 文件中,在 Menu 文件夹内添加以下标记。这些标记即移除您的 Paint 应用程序不需要的 GoTo 和 View 菜单。
<file name="GoTo_hidden"/>
<file name="View_hidden"/>
除了可手动添加上述标记外,您也可以在 Important Files 节点内删除 layer.xml 文件的 <this layer in context> 节点内的文件夹。
- 最后,再次运行应用程序并注意观察程序启动画面。一旦应用程序启动,请注意标题栏显示您指定的标题。而且有许多更小的菜单项、工具栏按钮和其他功能:
创建分发包
现在该选择分发媒介了。右键单击 PaintApp 节点并选择其中一个选项(如 Create ZIP Distribution),这会将整个应用程序与所有需要的模块和文件打包为一个 zip 文件。还可以选择 Build JNLP Application,这会创建您可以放到 Web 服务器上或直接链接到 Web 页上的应用程序的 JavaWebStart™ 版本(需要设置正确的 URL——生成的描述符使用 file:protocol,所以可以以本地方式测试您的可以 Web 启动的分发包)。
大功告成!构建在 NetBeans Platform 上的第一个完整应用程序完成。下一个教程是:NetBeans FeedReader Tutorial。