blob: 4fc212f0a96ba82303e78df0b8bcd2a985ecb9f4 [file] [log] [blame]
//
// 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[请将您的意见和建议发送给我们]