当前页面: 开发资料首页 → Netbeans 专题 → NetBeans IDE 5.0 Rich-Client Application 快速入门指南
摘要: NetBeans IDE 5.0 Rich-Client Application 快速入门指南 反馈 本文档帮助您学习使用 NetBeans IDE 5.0 在 NetBeans Platform 上...
本文档帮助您学习使用 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) 应用程序,这些都是使您的应用程序能被其他用户使用的重要工具。
单击 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 文件的库包装模块:
现在您需要一个模块来包含打算编写的实际代码。
单击 Finish。
IDE 创建 Paint 项目。该项目包含所有资源和项目元数据,如该项目的 Ant 构建脚本。该项目在 IDE 中打开。您可以在 Projects 窗口 (Ctrl-1) 中查看其逻辑结构,在 Files 窗口 (Ctrl-2) 中查看其文件结构。例如,Projects 窗口应该类似如下:
除本地化资源包和 XML 层之外,该项目还包括以下重要文件:
在学习本教程的过程中不需要修改任何这些文件。
您需要子类化几个属于 NetBeans API 的类。此外,该项目依赖 ColorChooser.jar 文件。所有 NetBeans API 都由插件模块实现,所以完成这两项任务仅仅意味着将一些插件模块添加插件模块列表,我们的插件模块运行时需要该列表。
下表第一栏列出了您将在本教程中子类化的所有类。在每种情况下,开始键入类名称并观察 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 类 |
下一步是创建用户可以在上面绘图的实际组件。这里,您可使用纯 Swing 组件——因此,我们跳过它实现的详细信息,并且只提供最终版本。您为其创建库包装模块颜色拾取器的 bean 用于此面板的源代码——运行完成的应用程序时,您将在编辑图像面板的工具栏中看到它。
现在可以编写第一个接触 NetBeans API 的类。它是一个 TopComponent 类。TopComponent 类只是一个 JPanel 类,NetBeans 的窗口操作系统知道如何与它对话——因此可以将它放入主窗口中包含选项卡的窗口内。
public class PaintTopComponent extends TopComponent implements ActionListener, ChangeListener {
注意您刚输入的类声明下的红色波浪线。将光标放在该线上并注意左边的空白处出现的电灯泡。单击该电灯泡(或按下 Alt-Enter),如下所示:
选择 Implement all abstract methods。IDE 即可生成两个方法框架:actionPerformed() 和 stateChanged()。稍后您要在本教程中填充这些框架。
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
public int getPersistenceType() { return PERSISTENCE_NEVER; } public String preferredID() { return "Image"; }
public PaintTopComponent() { initComponents(); String displayName = NbBundle.getMessage( PaintTopComponent.class, "UnsavedImageNameFormat", new Object[] { new Integer(ct++) } ); setDisplayName(displayName); }
这里的代码相当简单。首先调用的是您尚未编写的方法 initComponents(),它将向您的 TopComponent 添加一个工具栏和 PaintCanvas。因为您尚未编写该方法,所以在它下面出现红色波浪线。与以前一样,单击电灯泡(或按下 Alt-Enter)并接受建议:
这样就生成了 initComponents() 方法框架。
UnsavedImageNameFormat=Image {0}
确保在继续之前保存文件。
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); }
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()); }
LBL_Clear = Clear LBL_Foreground = Foreground LBL_BrushSize = Brush Size
确保在继续之前保存文件。
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()); }
MSG_SaveFailed = Could not write to file {0} MSG_Overwrite = {0} exists. Overwrite? MSG_Saved = Saved image to {0}
确保在继续之前保存文件。
使用 NetBeans 插件模块文件模板来建立该模块的功能的基础。使用文件模板时,IDE 将注册您在 layer.xml 文件中创建的项。使用向导创建文件模板后,可以使用 NetBeans API 继续开发该模块。
注意: 在什么位置放置动作并不重要,只要它在 File 菜单和 File 工具栏中即可。
在 Global Menu Item 部分选择 Separator Before。
现在应该看到下图:
单击 Next。
在 Icon 中,粘贴此图标(在这里右键单击它,然后将它保存在 org.netbeans.paint 文件夹中):
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 类。
public void performAction() { PaintTopComponent tc = new PaintTopComponent(); tc.open(); tc.requestActive(); }
此操作只创建我们的图像编辑组件的新实例,打开它,于是它出现在主窗口中,并且通过向它发送键盘焦点和选择其选项卡来激活它。
注意: 在什么位置放置动作并不重要,只要它在 File 菜单和 File 工具栏中即可。
在 Global Menu Item 部分选择 Separator After。
单击 Next。
在 Icon 中,粘贴此图标(在这里右键单击它,然后将它保存在 org.netbeans.paint 文件夹中):
IDE 在 org.netbeans.paint 中创建 SaveCanvasAction.java 并在 Source Editor 中打开它。
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 应用程序。
现在,在该模块项目的 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。