| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| |
| = NetBeans 平台绘图应用程序教程 |
| :jbake-type: platform_tutorial |
| :jbake-tags: tutorials |
| :jbake-status: published |
| :syntax: true |
| :source-highlighter: pygments |
| :toc: left |
| :toc-title: |
| :icons: font |
| :experimental: |
| :description: NetBeans 平台绘图应用程序教程 - Apache NetBeans |
| :keywords: Apache NetBeans Platform, Platform Tutorials, NetBeans 平台绘图应用程序教程 |
| |
| 本教程介绍了一些有关使用 NetBeans IDE 在 NetBeans 平台上开发富客户端 (rich client) 应用程序的基础知识。在 NetBeans 平台上开发应用程序时,实际上就是在 NetBeans IDE 的核心上进行开发。IDE 中与您的应用程序无关的所有模块均排除在外,只保留一些有用的模块。通过重用 IDE 核心中提供的现成功能,您可以节省许多时间和精力。 |
| |
| *注意:*本文档针对的是 NetBeans IDE 6.5 发行版。如果使用的是 NetBeans IDE 6.x,请参见 link:60/nbm-paintapp_zh_CN.html[本文档的 6.0/6.1 版]。 |
| |
| |
| |
| |
| |
| |
| |
| |
| == 绘图应用程序简介 |
| |
| 本教程旨在帮助您尽快入门。您将在 NetBeans 平台上创建并安装一个简单的应用程序。通过该应用程序,用户可以在屏幕上绘图并保存结果: |
| |
| |
| image::images/paintapp_result-without-menus-60.png[] |
| |
| 该初始版本还远非一个完善的绘图应用程序,它只是演示了一个在 NetBeans 平台上创建应用程序的非常简单的示例。 |
| |
| *注意:*如果您希望了解 NetBeans 模块(而不是富客户端 (rich client) 应用程序),则 link:nbm-google_zh_CN.html[NetBeans 插件快速入门]教程更适合您。 |
| |
| 在本教程中,我们重新创建一个作为样例随 IDE 一起提供的应用程序。要查看最终产品,或者要在完成本教程的过程中解决疑难问题,请从“新建项目”向导中如下所示的位置获取样例: |
| |
| |
| image::images/paintapp_sample-in-new-project-60.png[] |
| |
| |
| == 设置绘图应用程序 |
| |
| 在此部分,您将创建应用程序的结构。首先,您需要创建一个应用程序框架,可通过向导来完成此操作。该应用程序依赖于库,因此,您还会创建一个包含库的 JAR 文件的库包装模块。最后,将创建包含代码的模块。 |
| |
| |
| === 创建应用程序框架 |
| |
| 可以使用“NetBeans 平台应用程序”模板来创建应用程序框架。该框架包含一组模块,它们协同工作以形成应用程序的基础。将使用“项目属性”对话框来指定应用程序闪屏、应用程序名称以及要使用的 NetBeans 模块类型和数量。此外,您还可以利用一些操作,如创建 ZIP 分发和构建 Java WebStart (JNLP) 应用程序,它们是确保其他用户能够使用您的应用程序的重要工具。 |
| |
| |
| [start=1] |
| 1. 选择“文件”>“新建项目”。在“类别”下选择“NetBeans 模块”。在“项目”下,选择“NetBeans 平台应用程序”: |
| |
| |
| image::images/paintapp_paintapp-proj-wiz.png[] |
| |
| 单击“下一步”。 |
| |
| |
| [start=2] |
| 1. 在“名称和位置”面板的“项目名称”中键入 ``PaintApp`` 。将项目位置更改为计算机上的任意目录。将“设置为主项目”复选框保留为选中状态。单击“完成”。 |
| |
| 新应用程序框架在 IDE 中打开。它在“项目”窗口中包含两个节点。第一个节点(“模块”节点)用于在应用程序中手动添加模块和库包装模块。此外,在使用模块向导或库包装模块向导时,可以自动将创建的模块添加到应用程序中。 |
| |
| |
| === 创建库包装模块 |
| |
| 库包装模块是这样一个模块,其 JAR 文件不包含任何代码,它只是一个指向库的指针。该模块会将库转换为 NetBeans 模块,这样 NetBeans 类加载器系统的所有保护措施都会应用于该库,您无需对原始的 JAR 文件执行修改。然后您的应用程序就可以依赖于库了,就好像该库只是另外一个 NetBeans 模块一样。此外,如果库存在更新的版本,则只需为包装库分发单个的 NetBeans 模块 (NetBeans Module, NBM) 文件即可,无需分发其他任何内容。 |
| |
| *注意:*在 NetBeans 平台上构建应用程序的一个优点是:其用户界面基于 Java 的标准用户界面工具包 Swing。由于 Swing 已被广泛使用了很长时间,因此许多 Swing 组件都可以在应用程序中重用。在本教程中,您将重用现有的颜色选择器 JavaBean(可以在 NetBeans CVS 中的 ``contrib/coloreditor`` 下找到其源代码)。该 JAR 文件名为 ``ColorChooser.jar`` 。您可以从 link:http://web.archive.org/web/20081119053233/http://colorchooser.dev.java.net/[此处]下载库。将其保存到文件系统中的任意位置。 |
| |
| 请执行以下操作为 ``ColorChooser.jar`` 文件创建库包装模块: |
| |
| |
| [start=1] |
| 1. 选择“文件”>“新建项目”。在“类别”下选择“NetBeans 模块”。在“项目”下,选择“库包装模块”,然后单击“下一步”。 |
| |
| [start=2] |
| 1. 在“选择库”面板的“库”文本框中,键入 ``ColorChooser.jar`` 的路径,或者浏览到它所在的位置。 |
| |
| [start=3] |
| 1. 将“许可证”文本字段保留为空。如果希望分发完整的产品,则应该包括外部库的许可证文件。单击“下一步”。 |
| |
| [start=4] |
| 1. 在“名称和位置”面板中,填写项目名称,设置项目位置,并确保“添加到模块套件中”下拉列表显示模块将添加到应用程序中。单击“下一步”。 |
| |
| [start=5] |
| 1. 在“基本模块配置”面板的“代码名称基”中键入唯一名称,指定模块显示名称以及模块的本地化包位置: |
| |
| |
| image::images/paintapp_lib-wrap-1.png[] |
| |
| 单击“完成”。 |
| |
| 选定 ``colorchooser.jar`` 的包装模块是由 IDE 创建的。新模块的结构将显示在“项目”窗口中。应用程序结构中的“模块”节点显示模块是应用程序的一部分。 |
| |
| |
| === 创建模块 |
| |
| 现在,您需要使用一个模块来包含将要编写的实际代码。 |
| |
| |
| [start=1] |
| 1. 选择“文件”>“新建项目”。在“类别”下选择“NetBeans 模块”。在“项目”下选择“模块”,然后单击“下一步”。 |
| |
| [start=2] |
| 1. 在“名称和位置”面板的“项目名称”中键入 ``Paint`` 。将项目位置更改为计算机上的任意目录。确保“添加到模块套件中”单选按钮处于选定状态,并在“模块套件”下拉列表中选定了 ``PaintApp`` 应用程序。选中“设置为主项目”复选框。单击“下一步”。 |
| |
| [start=3] |
| 1. 在“基本模块配置”面板中,键入 ``org.netbeans.paint`` 。将“模块显示名称”保留为 ``Paint`` 。保留本地化包的位置。单击“生成 XML 层”,并且不更改建议的位置,以便将本地化包和 XML 层文件存储在名为 ``org.netbeans.paint`` 的包中。 |
| |
| 这些文件将执行以下操作: |
| |
| * *本地化包。*为国际化指定特定于语言的字符串。 |
| * *XML 层。*在 NetBeans 平台应用程序中注册菜单和工具栏按钮等项。 |
| |
| 单击“完成”。 |
| |
| IDE 将创建 ``Paint`` 项目。该项目包含所有源代码和项目 meta 数据,如项目的 Ant 生成脚本。此项目在 IDE 中打开。您可以在“项目”窗口 (Ctrl-1) 中查看其逻辑结构,在“文件”窗口 (Ctrl-2) 中查看其文件结构。例如,“项目”窗口应如下所示: |
| |
| |
| image::images/paintapp_paintapp-start-1.png[] |
| |
| 除了本地化包和 XML 层以外,此项目还包括以下重要文件: |
| |
| * *模块清单。*声明项目是一个模块。此外,它还设定了一些特定于模块的设置,如 XML 层的位置、本地化包的位置以及模块版本。 |
| * *生成脚本。*提供一个位置,供您创建自己的 Ant 目标并覆盖在 ``nbproject/build-impl.xml`` 中指定的 Ant 目标。 |
| * *项目 Meta 数据。*包含一些信息,如项目的类型、内容、平台、类路径、依赖关系以及项目命令与 Ant 脚本中的目标之间的映射。 |
| |
| 您在本教程中不需要修改其中的任何文件。 |
| |
| |
| === 指定模块的依赖关系 |
| |
| 您需要根据一些属于 link:http://bits.netbeans.org/dev/javadoc/index.html[NetBeans API] 的类创建子类。此外,该项目还依赖于 ``ColorChooser.jar`` 文件。由于所有 NetBeans API 都是由模块实现的,因此完成这两个任务实际上就意味着:将某些模块添加到保证我们的模块正常运行所需的模块列表中。 |
| |
| |
| [start=1] |
| 1. 在“项目”窗口中右键单击 ``Paint`` 项目节点,然后选择“属性”。“项目属性”对话框打开。在“类别”下单击“库”。 |
| |
| [start=2] |
| 1. 对于下表中列出的每个 API,单击“添加依赖关系...”,然后在“过滤器”文本框中开始键入要创建子类的类名称。 |
| |=== |
| |
| |*类* |*API* |*用途* |
| |
| | ``ColorChooser`` | ``ColorChooser`` |所创建的颜色选择器组件的库包装模块 |
| |
| | ``DataObject`` | ``Datasystems API`` |包含 DataObject 类的 NetBeans 模块 |
| |
| | ``DialogDisplayer`` | ``对话框 API`` |用于创建并显示用户通知(对话框的描述) |
| |
| | ``AbstractFile`` | ``文件系统 API`` |提供了以统一方式访问文件的通用 API |
| |
| | ``AbstractNode`` | ``节点 API`` |用作 NetBeans 中进行对象可视化的主要工具 |
| |
| | ``StatusDisplayer`` | ``UI 实用程序 API`` |用于编写主窗口中状态栏的 StatusDisplayer 类 |
| |
| | ``WeakListeners`` | ``实用程序 API`` |包含 WeakListeners 类 |
| |
| | ``TopComponent`` | ``窗口系统 API`` |包含 TopComponent JPanel 类 |
| |=== |
| |
| 上表中的第一列列出了将在本教程中创建子类的所有类。在每种情况下,当在“过滤器”中键入类名时,可观察到“模块”列表的选择范围逐渐缩小。使用表的第二列可以从缩小的“模块”列表中选取适当的 API(对于 ``ColorChooser`` ,应选取库),然后单击“确定”以确认选择: |
| |
| |
| image::images/paintapp_libfilter-60.png[] |
| |
| |
| [start=3] |
| 1. 单击“确定”退出“项目属性”对话框。 |
| |
| [start=4] |
| 1. 在“项目”窗口中,如果尚未展开 "Paint" 模块的项目节点,请将其展开。然后展开“重要文件”节点,再双击“项目 Meta 数据”节点。请注意,您所选择的 API 已声明为与该模块具有依赖关系。 |
| |
| |
| == 创建并嵌入画布 |
| |
| |
| === 创建画布 |
| |
| 下一步将创建用户可以在上面绘图的实际组件。对于本教程,您将使用一个纯 Swing 组件,因此,让我们跳过该组件的实现细节,只利用它的最终版本。在此面板的源代码中,将使用您已为其创建库包装模块的颜色选择器 Bean,当您运行完成的应用程序时,会在用于编辑图像的面板的工具栏中看到它。 |
| |
| |
| [start=1] |
| 1. 在“项目”窗口中,展开 ``Paint`` 节点,然后展开“源包”节点,再右键单击 ``org.netbeans.paint`` 节点。选择“新建”>“Java 类”。 |
| |
| [start=2] |
| 1. 在“类名”中输入 ``PaintCanvas`` 。请确保“包”中列出的是 ``org.netbeans.paint`` 。单击“完成”。 ``PaintCanvas.java`` 在源代码编辑器中打开。 |
| |
| [start=3] |
| 1. 将文件的缺省内容替换为 link:https://netbeans.apache.org/platform/guide/tutorials/paintTutorial/PaintCanvas.java[此处]的内容。如果为包指定 ``org.netbeans.paint`` 以外的名称,请在源代码编辑器中更正包名。 |
| |
| |
| === 准备 TopComponent 类 |
| |
| 现在您将编写第一个与 link:http://bits.netbeans.org/dev/javadoc/index.html[NetBeans API] 交互的类。它是一个 `` link:http://bits.netbeans.org/dev/javadoc/org-openide-windows/org/openide/windows/TopComponent.html[TopComponent]`` 类。 ``TopComponent`` 类正是一个 NetBeans 的窗口系统知道如何与其进行交互的 ``JPanel`` 类,因此可以将其置于主窗口中的标签化容器内。 |
| |
| |
| [start=1] |
| 1. 在“项目”窗口中,展开 ``Paint`` 节点,然后展开“源包”节点,再右键单击 ``org.netbeans.paint`` 节点。选择“新建”>“Java 类”。在“类名”中输入 ``PaintTopComponent`` 。请确保“包”中列出的是 ``org.netbeans.paint`` 。单击“完成”。 ``PaintTopComponent.java`` 在源代码编辑器中打开。 |
| |
| [start=2] |
| 1. 在该文件的顶部附近,将类声明改为以下代码: |
| |
| [source,java] |
| ---- |
| |
| public class PaintTopComponent extends TopComponent implements ActionListener, ChangeListener { |
| ---- |
| |
| |
| [start=3] |
| 1. 按 Ctrl-Shift-I 组合键修复导入,然后在对话框中单击“确定”。IDE 会将所需的 import 包声明置于文件顶部。 |
| |
| 请注意刚刚输入的类声明下面的红线。将光标放置在该行上,您会注意到左旁注显示了一个灯泡。单击该灯泡图标(或按 Alt-Enter 组合键),如下所示: |
| |
| |
| image::images/paintapp_lightbulb-60.png[] |
| |
| 选择“实现所有抽象方法”。IDE 生成两个方法框架 - ``actionPerformed()`` 和 ``stateChanged()`` 。您将在本教程的后面部分填充这些方法。 |
| |
| [start=4] |
| 1. 将以下三个变量声明添加到 ``PaintTopComponent`` 类的顶部,然后修复 import 语句 (Ctrl-Shift-I)。 |
| |
| [source,java] |
| ---- |
| |
| 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 |
| ---- |
| |
| |
| [start=5] |
| 1. 现在需要实现两个样板方法。第一个方法通知窗口系统在应用程序关闭时忽略打开的窗口;第二个方法提供一个基本字符串作为组件的唯一字符串 ID。每个 ``TopComponent`` 都有一个唯一的字符串 ID,此 ID 在保存 ``TopComponent`` 时使用。在 ``PaintTopComponent`` 类中插入以下两个方法: |
| |
| [source,java] |
| ---- |
| |
| @Override |
| public int getPersistenceType() { |
| return PERSISTENCE_NEVER; |
| } |
| |
| @Override |
| public String preferredID() { |
| return "Image"; |
| } |
| ---- |
| |
| 该类现在应如下所示: |
| |
| |
| [source,java] |
| ---- |
| |
| public class PaintTopComponent extends TopComponent implements ActionListener, ChangeListener { |
| |
| 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 PaintTopComponent() { |
| } |
| |
| @Override |
| public void actionPerformed(ActionEvent arg0) { |
| throw new UnsupportedOperationException("Not supported yet."); |
| } |
| |
| @Override |
| public void stateChanged(ChangeEvent arg0) { |
| throw new UnsupportedOperationException("Not supported yet."); |
| } |
| |
| @Override |
| public int getPersistenceType() { |
| return PERSISTENCE_NEVER; |
| } |
| |
| @Override |
| public String preferredID() { |
| return "Image"; |
| } |
| |
| } |
| ---- |
| |
| |
| === 初始化 TopComponent 类 |
| |
| 在此部分,我们添加初始化用户界面的代码。 |
| |
| |
| [start=1] |
| 1. 定义构造函数,然后修复 import 语句 (Ctrl-Shift-I): |
| |
| [source,java] |
| ---- |
| |
| public PaintTopComponent() { |
| |
| initComponents(); |
| |
| String displayName = NbBundle.getMessage( |
| PaintTopComponent.class, |
| "UnsavedImageNameFormat", |
| new Object[] { new Integer(ct++) } |
| ); |
| |
| setDisplayName(displayName); |
| |
| } |
| ---- |
| |
| 此处的代码非常简单。首先调用的是尚未编写的方法 ``initComponents()`` ,该方法用于在 ``TopComponent`` 中添加一个工具栏和一个 PaintCanvas。由于尚未编写该方法,因此它下面会显示一条红线。如前面所述,单击灯泡图标(或按 Alt-Enter 组合键),并接受建议的内容: |
| |
| |
| image::images/paintapp_lightbulb-initcomponents-60.png[] |
| |
| 将为您生成 ``initComponents()`` 方法框架。 |
| |
| |
| [start=2] |
| 1. 在“项目”窗口中展开 ``org.netbeans.paint`` 包。双击 ``Bundle.properties`` 文件,以便在源代码编辑器中将其打开。将以下代码行添加到该文件的末尾: |
| |
| [source,java] |
| ---- |
| |
| UnsavedImageNameFormat=Image {0} |
| ---- |
| |
| 此代码用于指定在用户保存一个新的图像文件之前,应用程序中标识此图像的文本。例如,当用户第一次在完成的应用程序中单击 "New Canvas" 时,源代码编辑器的上方将显示一个带有文本 'Image 0' 的标签。确保保存此文件,然后再继续。 |
| |
| |
| === 填充框架方法 |
| |
| 在此部分,我们将编写应用程序用户界面的代码。还可以使用 IDE 的 GUI 生成器以可视方式设计布局。 |
| |
| |
| [start=1] |
| 1. ``initComponents()`` 方法用于安装面板中的组件,以便用户可以与其进行交互。在上一节,已在 ``PaintTopComponent.java`` 类中生成了它的框架方法。请按如下所示填充该方法: |
| |
| [source,java] |
| ---- |
| |
| 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); |
| |
| } |
| ---- |
| |
| 按 Ctrl-Shift-I 组合键生成所需的 import 语句。 |
| |
| |
| [start=2] |
| 1. 填充您生成的另外两个方法。它们用于侦听 ``PaintTopComponent`` 类: |
| |
| [source,java] |
| ---- |
| |
| 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()); |
| |
| } |
| ---- |
| |
| |
| [source,java] |
| ---- |
| |
| public void stateChanged(ChangeEvent e) { |
| |
| JSlider js = (JSlider) e.getSource(); |
| canvas.setDiam (js.getValue()); |
| preview.paintImmediately(0, 0, preview.getWidth(), preview.getHeight()); |
| |
| } |
| ---- |
| |
| |
| [start=3] |
| 1. 在 ``Bundle.properties`` 文件的末尾添加以下键值对: |
| |
| [source,java] |
| ---- |
| |
| LBL_Clear = Clear |
| LBL_Foreground = Foreground |
| LBL_BrushSize = Brush Size |
| |
| ---- |
| |
| 确保保存此文件,然后再继续。 |
| |
| |
| === 将图像保存到硬盘 |
| |
| 在新的应用程序中,允许用户保存所创建的图像是一个非常好的想法。在 ``PaintTopComponent`` 类中包括以下代码可激活此功能。 |
| |
| |
| [start=1] |
| 1. 在 ``PaintTopComponent`` 类中插入以下代码: |
| |
| [source,java] |
| ---- |
| |
| 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()); |
| |
| } |
| ---- |
| |
| |
| [start=2] |
| 1. 将以下代码行添加到 ``Bundle.properties`` 文件中: |
| |
| [source,java] |
| ---- |
| |
| MSG_SaveFailed = Could not write to file {0} |
| MSG_Overwrite = {0} exists. Overwrite? |
| MSG_Saved = Saved image to {0} |
| ---- |
| |
| 确保保存此文件,然后再继续。 |
| |
| |
| [start=3] |
| 1. 按 Ctrl-Shift-I 组合键修复 import 语句。您会注意到 ``File`` 类有两个全限定名称。请选择 ``java.io.File`` 选项。 |
| |
| |
| == 创建 "New Canvas" 菜单项 |
| |
| 使用“模块开发”文件模板,可以创建基本的模块功能。使用文件模板时,IDE 在 ``layer.xml`` 文件中注册您创建的项。使用向导创建文件模板后,您可以使用 link:https://bits.netbeans.org/dev/javadoc/[NetBeans API] 继续开发模块。 |
| |
| |
| [start=1] |
| 1. 在“项目”窗口中右键单击 Paint 模块的项目节点,然后选择“新建”>“其他”。在“新建文件”向导中的“类别”下选择“模块开发”,然后在“文件类型”下选择“操作”。单击“下一步”。 |
| |
| [start=2] |
| 1. 在“操作类型”面板中,接受缺省设置。单击“下一步”。 |
| |
| [start=3] |
| 1. 在“GUI 注册”面板中,选择“全局菜单项”,然后选择“全局工具栏按钮”。设置以下值: |
| * *类别:*编辑 |
| * *菜单:*文件 |
| * *位置:*您需要的任何位置! |
| * *工具栏:*文件 |
| * *位置:*您需要的任何位置! |
| |
| *注意:*将操作置于什么位置并不重要,只要在“文件”菜单和“文件”工具栏中即可。 |
| |
| 您现在应该看到如下所示的屏幕: |
| |
| |
| image::images/paintapp_newcanvasaction-60.png[] |
| |
| 单击“下一步”。 |
| |
| |
| [start=4] |
| 1. 在“名称、图标和位置”面板的“类名”中键入 ``NewCanvasAction`` ,并在“显示名称”中键入 ``New Canvas`` 。 |
| |
| 在“图标”中,浏览至以下图标(右键单击该图标,然后将其保存在 ``org.netbeans.paint`` 文件夹中): |
| image::images/paintapp_new_icon.png[] |
| |
| |
| [start=5] |
| 1. 单击“完成”。 |
| |
| IDE 在 ``org.netbeans.paint`` 中创建 ``NewCanvasAction.java`` ,并在源代码编辑器中将其打开。将会显示以下内容: |
| |
| |
| [source,java] |
| ---- |
| |
| /* |
| * To change this template, choose Tools | Templates |
| * and open the template in the editor. |
| */ |
| package org.netbeans.paint; |
| |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| |
| public final class NewCanvasAction implements ActionListener { |
| |
| public void actionPerformed(ActionEvent e) { |
| // TODO implement action body |
| } |
| |
| } |
| ---- |
| |
| 与“GUI 注册”面板中指定的一样,IDE 在 ``layer.xml`` 文件中将操作类注册为菜单项和工具栏按钮,该文件还包含有关图标和显示名称的信息。 |
| |
| |
| [start=6] |
| 1. 在源代码编辑器中,打开 ``NewCanvasAction.java`` ,然后按如下所示填充 ``actionPerformed()`` 方法: |
| |
| [source,java] |
| ---- |
| |
| public void actionPerformed(ActionEvent e) { |
| PaintTopComponent tc = new PaintTopComponent(); |
| tc.open(); |
| tc.requestActive(); |
| } |
| ---- |
| |
| 该方法的作用只是创建一个图像编辑组件的新实例、打开该实例(使其显示在主窗口中),以及通过向其发送键盘焦点和选择其标签来激活该实例。 |
| |
| |
| == 创建 "Save Canvas" 菜单项 |
| |
| 像上一节一样,使用“新建操作”向导来创建一个菜单项,但这次是用来保存图像。 |
| |
| |
| [start=1] |
| 1. 在“项目”窗口中右键单击 Paint 模块的项目节点,然后选择“新建”>“其他”。在“新建文件”向导中的“类别”下选择“模块开发”,然后在“文件类型”下选择“操作”。单击“下一步”。 |
| |
| [start=2] |
| 1. 在“操作类型”面板中,接受缺省设置。单击“下一步”。 |
| |
| [start=3] |
| 1. 在“GUI 注册”面板中,选择“全局菜单项”,然后选择“全局工具栏按钮”。设置以下值: |
| * *类别:*编辑 |
| * *菜单:*文件 |
| * *位置:*您需要的任何位置! |
| * *工具栏:*文件 |
| * *位置:*您需要的任何位置! |
| |
| *注意:*将操作置于什么位置并不重要,只要在“文件”菜单和“文件”工具栏中即可。 |
| |
| 单击“下一步”。 |
| |
| [start=4] |
| 1. 在“名称、图标和位置”面板的“类名”中键入 ``SaveCanvasAction`` ,并在“显示名称”中键入 ``Save Canvas`` 。 |
| |
| 在“图标”中,粘贴以下图标(右键单击该图标,然后将其保存到 ``org.netbeans.paint`` 文件夹中): |
| |
| |
| image::images/paintapp_save_icon.png[] |
| |
| [start=5] |
| 1. 单击“完成”。 |
| |
| IDE 在 ``org.netbeans.paint`` 中创建 ``SaveCanvasAction.java`` ,并在源代码编辑器中将其打开。 |
| |
| |
| [start=6] |
| 1. 更改类签名,以扩展 ``CallableSystemAction`` 并实现 ``PropertyChangeListener`` : |
| |
| [source,java] |
| ---- |
| |
| public final class SaveCanvasAction extends CallableSystemAction implements PropertyChangeListener |
| ---- |
| |
| |
| [start=7] |
| 1. 在源代码编辑器中,确保打开 ``SaveCanvasAction.java`` ,然后按如下所示填充 ``actionPerformed()`` 方法: |
| |
| [source,java] |
| ---- |
| |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| 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(); |
| |
| } |
| } |
| ---- |
| |
| 按 Ctrl-Shift-I 组合键生成所需的 import 语句: |
| |
| |
| image::images/paintapp_fiximports-60.png[] |
| |
| [start=8] |
| 1. 按如下方式填充 ``CallableSystemAction`` 类中的方法: |
| |
| [source,java] |
| ---- |
| |
| @Override |
| public String getName() { |
| return "Save Canvas"; |
| } |
| |
| @Override |
| public HelpCtx getHelpCtx() { |
| return null; |
| } |
| |
| ---- |
| |
| |
| [start=9] |
| 1. 按如下方式填充 ``PropertyChangeListener`` 中的 ``propertyChange()`` 方法: |
| |
| [source,java] |
| ---- |
| |
| @Override |
| public void propertyChange(PropertyChangeEvent evt) { |
| |
| if (TopComponent.Registry.PROP_ACTIVATED.equals(evt.getPropertyName())){ |
| updateEnablement(); |
| } |
| |
| } |
| ---- |
| |
| 当出现红线时,单击 Alt + Enter 组合键可以使 IDE 在 ``SaveCanvasAction`` 类中创建 ``updateEnablement()`` 方法。 |
| |
| |
| [start=10] |
| 1. 接下来,定义 ``updateEnablement()`` 方法: |
| |
| [source,java] |
| ---- |
| |
| private void updateEnablement() { |
| |
| setEnabled(TopComponent.getRegistry().getActivated() |
| instanceof PaintTopComponent); |
| |
| } |
| ---- |
| |
| |
| [start=11] |
| 1. 最后,定义构造函数: |
| |
| [source,java] |
| ---- |
| |
| public SaveCanvasAction() { |
| |
| TopComponent.getRegistry().addPropertyChangeListener ( |
| WeakListeners.propertyChange(this, |
| TopComponent.getRegistry())); |
| |
| updateEnablement(); |
| |
| } |
| ---- |
| |
| 当出现红线时,单击 Alt + Enter 组合键可以使 IDE 导入 ``org.openide.util.WeakListeners`` 。 |
| |
| 代码的主要目的在于添加属性更改侦听程序。 ``TopComponent.Registry`` 是系统中所有打开的 ``TopComponents`` (即所有打开的标签)的注册表。我们的目的是要对该注册表进行侦听以获知其更改,并根据焦点所在的对象启用和禁用操作。 |
| |
| *注意:*您在此调用的是 ``WeakListeners.propertyChange()`` ,而不是直接连接属性更改侦听程序。这样做的目的在于:生成的属性更改侦听程序对操作造成的影响较弱。实际上,只要该应用程序是打开的,您的操作就会处于活动状态,因此,作为一种最佳做法(同时出于前瞻性的考虑),当您打算连接侦听程序,但又不存在中断调用侦听程序的代码时,建议使用弱化的侦听程序。否则,会出现潜在的内存泄漏 - 由于注册表在其侦听程序列表中一直保存着对该操作的引用,因此不会对该操作进行垃圾回收。 |
| |
| 以下是您现在应该在“项目”窗口中看到的内容: |
| |
| |
| image::images/paintapp_final-paint-module.png[] |
| |
| |
| == 包装 |
| |
| 当然,您希望创建的是尽善尽美的应用程序,因此,您最后可能还需要再执行几个步骤。首先,为应用程序创建闪屏,然后创建 ZIP 分发文件和 JNLP 应用程序。 |
| |
| |
| [start=1] |
| 1. 运行 ``PaintApp`` 项目。该应用程序启动后,将主屏幕适当缩小,然后绘制一个闪屏。使用“保存”按钮保存该闪屏。 |
| |
| [start=2] |
| 1. 在原始项目中,右键单击 ``PaintApp`` 节点,选择“属性”,然后在“项目属性”对话框中单击“生成”。 |
| |
| [start=3] |
| 1. 选择“创建独立的应用程序”。现在可以指定标记名称(将是 IDE 可以为您生成的启动器名称)和应用程序标题(将显示在应用程序的标题栏中)。缺省情况下,您会看到以下内容: |
| |
| |
| image::images/paintapp_splashscreen1-60.png[] |
| |
| |
| [start=4] |
| 1. 单击“闪屏”。浏览到您的闪屏。如果没有闪屏,可以使用 link:https://netbeans.apache.org/platform/images/tutorials/paintapp/splash.gif[此闪屏]。单击“确定”将其添加到应用程序中: |
| |
| |
| image::images/paintapp_splashscreen-60.png[] |
| |
| |
| [start=5] |
| 1. 现在,在 Paint 模块的 ``layer.xml`` 文件中,将以下标记添加到 "Menu" 文件夹中。这些标记用于删除 Paint 应用程序不需要的 "GoTo" 和 "View" 菜单。 |
| |
| [source,java] |
| ---- |
| |
| <file name="GoTo_hidden"/> |
| <file name="View_hidden"/> |
| ---- |
| |
| 或者,也可以删除 ``layer.xml`` 文件的 ``<上下文中的此层>`` 节点中的文件夹,而不是手动添加上述标记。为此,请展开 ``<上下文中的此层>`` ,然后展开 "Menu Bar" 节点。右键单击 "GoTo" 和 "View" 节点,然后从弹出式菜单中选择“删除”。 |
| |
| |
| [start=6] |
| 1. 最后,再次运行该应用程序,请注意观察闪屏。应用程序启动后,您可以看到标题栏中将显示您所指定的标题。此外,还少了很多菜单项、工具栏按钮和其他功能: |
| image::images/paintapp_result-without-menus-60.png[] |
| |
| |
| == 创建分发 |
| |
| 现在该选择分发介质了。右键单击 ``PaintApp`` 节点,并选择“生成 ZIP 分发”,以便将整个应用程序连同所有需要的模块和文件一起打包为一个 zip 文件。此外,还可以选择“生成 JNLP 应用程序”来创建 JavaWebStart 版本的应用程序,您可以将该版本的应用程序放到 Web 服务器上,并直接通过 Web 页链接到该应用程序(您需要设置正确的 URL - 生成的描述符使用 file: 协议才能在本地对可通过 Web 启动的分发进行测试)。 |
| |
| 以上就是本教程的内容!您已完成了在 NetBeans 平台上构建绘图应用程序的过程。下一站: link:https://netbeans.apache.org/tutorials/nbm-feedreader.html[NetBeans 平台 Feed Reader 教程]。 |
| |
| link:http://netbeans.apache.org/community/mailing-lists.html[请将您的意见和建议发送给我们] |