// 
//     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.
//

= 在 Java 应用程序中绑定 Bean 和数据
:jbake-type: tutorial
:jbake-tags: tutorials 
:jbake-status: published
:icons: font
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:description: 在 Java 应用程序中绑定 Bean 和数据 - Apache NetBeans
:keywords: Apache NetBeans, Tutorials, 在 Java 应用程序中绑定 Bean 和数据

本指南介绍了 NetBeans IDE 对 Java 应用程序中 Bean 绑定和数据绑定的支持。


image::images/netbeans-stamp-80-74-73.png[title="此页上的内容适用于 NetBeans IDE 7.1、7.2、7.3、7.4 和 8.0"]


*要学完本教程，您需要具备以下软件和资源。*

|===
|软件或资源 |要求的版本 

|link:https://netbeans.org/downloads/index.html[+NetBeans IDE+] |版本 7.1、7.2、7.3、7.4 或 8.0 

|link:http://www.oracle.com/technetwork/java/javase/downloads/index.html[+Java 开发工具包 (JDK)+] |版本 6 或更高版本 
|===


== 简介：NetBeans IDE 中的 Bean 绑定

在发布 Bean 绑定库之前，将 UI 组件连接到数据库或将组件属性的值保持同步非常麻烦。例如，将标准数据库中的数据显示在 JTable 中需要手动创建实用程序类来处理数据库与 JTable 之间的连接。而且让不同 Bean 属性的值保持同步（如呈现可视 Bean 的 JTextField 值）需要手动编码监听程序和事件处理程序。

Bean 绑定库对所有这些操作进行了简化和标准化。只需编写几行代码确定哪些组件的哪些属性需要保持同步，Bean 绑定库就可以处理其余的操作。在 NetBeans IDE 中，Bean 绑定功能集成在 GUI 构建器中，因此，在建立可视设计之后可以快速获取已编码应用程序的行为。

本指南概述了 IDE 中 Bean 绑定的主要功能。


== 将属性绑定到其他属性

就最基本的用途而言，Bean 绑定是一种不使用事件监听和处理代码连接 Bean 属性的方法。

为了说明 Bean 绑定的概念以及 IDE 如何支持该绑定，我们将举一个简单的示例，其中用户可以调整滑块来更改文本字段中的数值。

*设置示例：*

1. 在 IDE 中，选择 "File"（文件）> "New Project"（新建项目）。
2. 选择 "Java" 类别，然后选择 "Java Application"（Java 应用程序）模板。单击 "Next"（下一步）。
3. 在向导的 "Name and Location"（名称和位置）页中，执行以下操作：
* 键入  ``NumberSlider``  作为项目名称。
* 将 "Use Dedicated Folder for Storing Libraries"（使用专用文件夹存储库）复选框保留为取消选中状态。

[.feature]
--
image:images/numberslider-small.png[role="left", link="images/numberslider.png"]
--

* 清除 "Create Main Class"（创建主类）复选框。

[start=4]
. 单击 "Finish"（完成）退出向导并设置项目。

[start=5]
. 在 "Projects"（项目）窗口中，右键单击 NumberSlider 项目节点并选择 "New"（新建）> "JFrame Form"（JFrame 窗体）。

（如果 "JFrame Form"（JFrame 窗体）在 "New"（新建）菜单中不可用，则选择 "Other"（其他）。然后在新建文件向导中，选择 "Swing GUI Forms"（Swing GUI 窗体）类别，然后选择 "JFrame Form"（JFrame 窗体）模板。）


[start=6]
. 在向导的 "Name and Location"（名称和位置）页中，执行以下操作：
* 为类名键入  ``NumberSliderFrame`` 。
* 为包名键入  ``numberslider`` 。

[.feature]
--
image::images/numberslider2-small.png[role="left", link="images/numberslider2.png"]
--


[start=7]
. 单击 "Finish"（完成）退出向导并创建窗体。

 ``NumberSliderFrame.java``  应以设计模式在编辑区域中打开。


[start=8]
. 从组件面板的 "Swing Controls"（Swing 控件）部分，将一个滑块组件拖至设计区域。（如果 "Palette"（组件面板）窗口未打开，请选择 "Window"（窗口）> "Palette"（组件面板）。）

[start=9]
. 从组件面板中，将一个文本字段组件拖至设计区域。

生成的窗体可能类似于下面的屏幕快照。不过，对于本示例而言，定位并不重要。

[.feature]
--
image::images/slider-textfield-small.png[role="left", link="images/slider-textfield.png"]
--


=== 源和目标

现在我们已经设置了该示例，下面可以创建绑定了。不过，我们首先需要确定哪个组件作为绑定的_源_，哪个组件作为绑定的_目标_。绑定源组件表示绑定属性值的来源。

在 GUI 编辑器中进行绑定时，开始先进行目标绑定，然后在 "Bind"（绑定）对话框中声明绑定源。

在本例中，由于 JSlider 附带一个默认值范围，因此我们将使用它作为源。

*注：*绑定可以是双向的（读/写），这样，在目标中所做的更改可以自动地反映在源中。但是，初始绑定方向始终从源到目标。请参见<<prop-advanced,高级绑定配置>>一节中有关“更新模式”的信息。

*将滑块绑定到文本字段：*

1. 右键单击文本字段组件，并选择 "Bind"（绑定）> "text"（文本）以打开 "Bind"（绑定）对话框。
2. 从 "Binding Source"（绑定源）组合框中，选择  ``jSlider1`` 。
3. 从 "Binding Expression"（绑定表达式）组合框中，选择  ``value int`` ，如下图所示。

[.feature]
--
image::images/bind-dialog-small.png[role="left", link="images/bind-dialog.png"]
--


[start=4]
. 单击 "OK"（确定）。

刚才将滑块的  ``value``  Bean 属性绑定到了文本字段的  ``text``  值。

在设计区域，文本字段应显示值  ``50`` 。此值说明滑块处于中间位置，并且滑块的默认值范围为 0 到 100。

现在可以运行该应用程序并查看工作中的绑定。

选择 "Run"（运行）> "Run File"（运行文件）以运行文件。

应用程序应在单独的窗口中启动。在运行的应用程序中调整滑块，并查看文本字段中值的更改。

image::images/run-numberslider.png[]


== 绑定定制 Bean

在上一节中，您绑定了从组件面板添加到窗体的两个标准 Swing 组件的属性。还可以绑定其他 Bean 的属性。不过，要执行此操作，您需要执行一些步骤，让 IDE 用于生成绑定代码的功能使该 Bean 可用。可以采取以下任一方法使 IDE 的绑定功能可用于 Bean：

* 将 Bean 添加到组件面板，以便可以像添加标准 Swing 组件那样将其添加到窗体。
* 将 Bean 类添加到您的项目并编译该 Bean。

将 Bean 添加到“组件面板”窗口：

1. 确保编译了 Bean。
2. 选择“工具”>“组件面板”>“Swing/AWT 组件”。
3. 如果要为 Bean 创建新的组件面板类别，请在添加 Bean 之前单击“新建类别”，然后输入所需的名称。
4. 单击“从 JAR 添加”、“从库添加”或“从项目添加”，完成添加 Bean 的向导操作。

从项目添加 Bean：

1. 在“项目”窗口中，右键单击 Bean 的节点并选择“编译文件”。
2. 将 Bean 拖至窗体。

然后您应在“检查器”窗口中看到此 Bean。接着可以为该 Bean 的任何属性调用“绑定”对话框。


== 高级绑定配置

本教程第一节中的示例介绍了与某些默认行为的简单绑定。但是，有时您可能希望或需要以不同方式配置绑定。如果是这种情况，则可以使用“绑定”对话框的“高级”标签。

该对话框的“高级”标签中包含以下字段：

* *名称*。可用于创建绑定的名称，这可以让您更为灵活地管理绑定。该名称将添加到绑定的构造函数中，可使用绑定的  ``getName()``  方法来引用它。
* *更新模式*。指定保持属性同步的方式。可能的值为：
* *始终同步 (读/写)*。不论何时对源或目标之一进行了更改，另一个也将更新。
* *只能从源中读取 (只读)*。仅在首次设置源值时更新目标。将在目标中更新对源所做的更改。不会在源中更新对目标所做的更改。
* *从源中读取一次 (读取一次)*。仅在初始绑定目标和源时才更新目标。
* *更新源的时间*（仅在绑定 JTextField 和 JTextArea 组件的  ``text``  属性时才出现此选项）。用于选择同步属性的频率。
* *忽略调整*（仅在绑定 JSlider 的  ``value``  属性、JTable 和 JList 的  ``selectedElement``  属性以及 JTable 和 JList 的  ``selectedElements``  属性时才出现此选项）。如果选中此复选框，则只有在用户完成更改后，才会将某一属性的任意更改应用到另一个属性中。例如，当应用程序用户拖动滑块时，只有在用户松开鼠标按钮后，才会更新滑块的  ``value``  属性所绑定的属性值。
* *转换器*。如果绑定涉及到具有不同数据类型的属性，则可以指定在类型之间转换值的代码。Bean 绑定库可处理很多常用转换，但对于其他属性类型的组合，则可能需要提供您自己的转换器。此类转换器需要扩展  ``org.jdesktop.beansbinding.Converter``  类。

“转换器”下拉列表中填充了已作为 Bean 添加到窗体中的任何转换器。还可以使用以下方法直接添加转换代码：单击省略号 (...) 按钮，然后从“使用以下内容选择转换器属性”下拉列表中选择“定制代码”。

下面列出了不需要提供转换器的转换：

* 将 BigDecimal 转换为字符串型，将字符串型转换为 BigDecimal
* 将 BigInteger 转换为字符串型，将字符串型转换为 BigInteger
* 将布尔型转换为字符串型，将字符串型转换为布尔型
* 将字节型转换为字符串型，将字符串型转换为字节型
* 将字符型转换为字符串型，将字符串型转换为字符型
* 将双精度型转换为字符串型，将字符串型转换为双精度型
* 将浮点型转换为字符串型，将字符串型转换为浮点型
* 将整型转换为字符串型，将字符串型转换为整型
* 将长整型转换为字符串型，将字符串型转换为 BigDecimal
* 将短整型转换为字符串型，将字符串型转换为短整型
* 将整型转换为布尔型，将布尔型转换为整型
* *验证器*。可用于指定代码以验证在目标属性值中的更改，然后再将该更改传播回源属性。例如，您可以使用验证器确保整型属性值在指定的范围内。

验证器需要扩展  ``org.jdesktop.beansbinding.Validator``  类。
“验证器”下拉列表中填充了已作为 Bean 添加到窗体中的任何验证器。还可以使用以下方法直接添加验证代码：单击省略号 (...) 按钮，然后从“使用以下内容选择验证器属性”下拉列表中选择“定制代码”。

* *空值源值*。可用于在尝试绑定时源属性具有 ``空`` 值的情况下指定使用其他值。该字段与  ``org.jdesktop.beansbinding.Binding``  类的  ``setSourceNullValue()``  方法相对应。
* *不可读源值*。可用于在尝试绑定时无法解析绑定表达式的情况下指定使用其他值。该字段与  ``org.jdesktop.beansbinding.Binding``  类的  ``setSourceUnreadableValue()``  方法相对应。

*注：*为了更好地了解上面提到的类和方法，可以从 IDE 中直接访问 Bean 绑定 Javadoc 文档。选择“帮助”>“Javadoc 参考”>“Bean 绑定”。在打开的浏览器窗口中，单击  ``org.jdesktop.beansbinding``  链接以访问这些类的文档。


== 将数据绑定到组件

除了同步可视 Swing 组件和其他定制 Bean 的属性之外，还可以使用 Bean 绑定帮助您使用可视组件与数据库交互。在创建新的 Java 窗体并在窗体中添加组件后，您可以生成代码，以便将这些组件绑定到数据上。本节介绍如何将数据绑定到 Swing JTable、JList 和 JComboBox 组件。

在将组件绑定到数据库中的数据之前，您需要完成以下操作：

* 在 IDE 中连接到数据库。
* 创建一些类，用于表示要绑定的数据库表。下面介绍了创建实体类以便将数据绑定到组件的步骤。


=== 创建实体类

*创建实体类以表示要绑定到 JTable 的数据库：*

1. 在 "Projects"（项目）窗口中，右键单击项目并选择 "New"（新建）> "Other"（其他），选择 "Persistence"（持久性）类别，然后选择 "Entity Classes from Database"（通过数据库生成实体类）模板。
2. 在向导的 "Database Tables"（数据库表）页中，选择数据库连接。
3. 在 "Available Tables"（可用表）列被填充后，选择要在应用程序中使用的表，然后单击 "Add"（添加），以便将表移到 "Available Tables"（选定的表）列中。单击 "Next"（下一步）。

[.feature]
--
image::images/entity-wizard1-small.png[role="left", link="images/entity-wizard1.png"]
--


[start=4]
. 在该向导的 "Entity Classes"（实体类）页中，确保选中了 "Generate Named Query Annotations for Persistent Fields"（为持久性字段生成已命名的查询标注）和 "Create Persistence Unit"（创建持久性单元）复选框。

[.feature]
--
image::images/entity-wizard2-small.png[role="left", link="images/entity-wizard2.png"]
--


[start=5]
. 对生成类的名称及其位置进行任何所需的定制。

[start=6]
. 单击 "Finish"（完成）。

在 "Projects"（项目）窗口中，您会看到实体类的节点。


=== 将组件绑定到表示数据的 Bean

本节介绍如何将数据绑定到 JTable、JList 和 JComboBox 组件。

*将一个数据库表添加到窗体，并自动生成 JTable 以显示数据库表的内容：*

1. 打开 "Services"（服务）窗口。
2. 连接到包含您要添加到窗体的表的数据库。（可以通过右键单击用于数据库连接的节点并选择 "Connect"（连接）以连接到数据库。）

*注：*本教程使用  ``sample [app on App]``  数据库，通过选择 "Services"（服务）窗口，展开 "Databases"（数据库）节点，右键单击数据库连接节点 ( ``jdbc:derby://localhost:1527/sample[app on APP]`` )，然后从上下文菜单中选择 "Connect"（连接），可连接到该数据库。
如果系统提示您提供用户 ID 和口令，请指定  ``app``  作为用户 ID，并指定  ``app``  作为口令。


[start=3]
. 展开用于连接的节点，并展开其表节点。

[start=4]
. 将表节点拖到窗体并在拖至表时按住 Ctrl 键。

这将创建 JTable，并将其列绑定到数据库表中的列。

*将数据库表绑定到现有的 JTable 组件：*

1. 在 GUI 构建器中右键单击该组件，然后选择 "Bind"（绑定）> "elements"（元素）。

[.feature]
--
image::images/bind-dialog-table-small.png[role="left", link="images/bind-dialog-table.png"]
--


[start=2]
. 单击 "Import Data to Form"（将数据导入窗体）。在 "Import Data to Form"（将数据导入窗体）对话框中，选择要将组件绑定到的数据库表。单击 "OK"（确定）。

[start=3]
. 在 "Binding Source"（绑定源）组合框中，选择表示实体类结果列表的项。例如，如果调用实体类  ``Customer.java`` ，则列表对象将生成为  ``customerList`` 。

[.feature]
--
image::images/source-selected-small.png[role="left", link="images/source-selected.png"]
--


[start=4]
. 将绑定表达式的值保留为 ``空值`` 。

[start=5]
. 如果不想在 JTable 中显示某些数据库列，请在 "Selected"（选定）列表中选择这些列，然后将它们移到 "Available"（可用）列表中。

[start=6]
. 选择 "Advanced"（高级）标签进一步配置绑定内容。例如，您可以指定验证器或转换器，或者指定绑定源为空值或不可读时的行为。

[start=7]
. 单击 "OK"（确定）。

*将数据绑定到 JList 组件：*

1. 在 GUI 构建器中右键单击该组件，然后选择 "Bind"（绑定）> "elements"（元素）。
2. 单击 "Import Data to Form"（将数据导入窗体）。在 "Import Data to Form"（将数据导入窗体）对话框中，选择要将组件绑定到的数据库表。单击 "OK"（确定）。
3. 在 "Binding Source"（绑定源）组合框中，选择表示实体类结果列表的项。例如，如果调用实体类  ``Customer.java`` ，则列表对象将生成为  ``customerList`` 。

[.feature]
--
image::images/jlist-binding-small.png[role="left", link="images/jlist-binding.png"]
--


[start=4]
. 将绑定表达式的值保留为 ``空值`` 。

[start=5]
. 在 "Display Expression"（显示表达式）下拉列表中，选择表示数据库列的属性，该列包含了要在列表中显示的值。

[start=6]
. 选择 "Advanced"（高级）标签进一步配置绑定内容。

[start=7]
. 单击 "OK"（确定）。

*将数据绑定到 JComboBox 组件：*

1. 右键单击组合框，然后选择 "Bind"（绑定）> "elements"（元素）。
2. 单击 "Import Data to Form"（将数据导入窗体）。在 "Import Data to Form"（将数据导入窗体）对话框中，选择要将组件绑定到的数据库表。单击 "OK"（确定）。
3. 在 "Binding Source"（绑定源）组合框中，选择表示实体类结果列表的项。例如，如果调用实体类  ``Customer.java`` ，则列表对象将生成为  ``customerList`` 。

[.feature]
--
image::images/combo-binding-small.png[role="left", link="images/combo-binding.png"]
--


[start=4]
. 将绑定表达式值保留为 ``空值`` ，然后单击 "OK"（确定）。

[start=5]
. 再次右键单击组合框，然后选择 "Bind"（绑定）> "selectedItem"。

[start=6]
. 绑定到您希望受用户选择影响的属性。

image::images/combo-item.png[]


[start=7]
. 单击 "OK"（确定）保存所做的编辑。

Bean 绑定库（从版本 1.2.1 起）没有 DetailBinding 类，该类用于指定如何为 JComboBox 派生 _display_ 值。因此，您需要编写一些定制代码。一种方法是编写定制单元格呈现器，如下所示。

*要正确呈现组合框，请执行以下操作：*

1. 选择组合框。
2. 在 "Properties"（属性）窗口的 "Properties"（属性）标签中，选择呈现属性。
3. 单击省略号 (...) 按钮。
4. 在属性编辑器顶部的组合框中，选择 "Custom Code"（定制代码）。
5. 在文本区域中，输入类似以下内容的代码，其中 `jComboBox1` 是 JComboBox 实例的名称，`MyEntityClass` 是实体类，`getPropertyFromMyEntityClass()` 是实体类中要绑定的属性的 getter。

[source,java]
----

jComboBox1.setRenderer(new DefaultListCellRenderer() {
           @Override
           public Component getListCellRendererComponent(
                   JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
               super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
               if (value instanceof MyEntityClass) {
                   MyEntityClass mec = (MyEntityClass)value;
                   setText(mec.getPropertyFromMyEntityClass());
               }
               return this;
           }
            })
----

[.feature]
--
image::images/custom-small.png[role="left", link="images/custom.png"]
--

*注：*您还可以在其自身的源文件中创建定制呈现器，编译文件，将呈现器拖至窗体，然后设置组合框的呈现器属性以使用此 Bean。


== 特殊绑定属性

根据需要，Bean 绑定库可为某些 Swing 组件提供特殊合成属性（这些组件本身没有这些属性）。这些属性表示用于绑定到其他属性的内容，如选定的表行。

下面列出了 Bean 绑定库添加的一组合成属性：

|===
|组件 |属性 |描述 

|AbstractButton |selected |按钮的选定状态。 

|JComboBox |selectedItem |JComboBox 的选定项。 

|JSlider |value |JSlider 值；通知所有更改。 

|value_IGNORE_ADJUSTING |与 "value" 基本相同，但在滑块调整值时不通知更改。 

|JList |selectedElement |JList 的选定元素；通知所有更改。如果在 JListBinding 中将 JList 作为目标，则会将单个选定元素报告为绑定源列表中的元素。否则，将该选定元素报告为列表模型中的对象。如果未选择任何内容，则该属性的值为 ``空值`` 。 

|selectedElements |JList 的多个选定元素的列表；通知所有更改。如果在 JListBinding 中将 JList 作为目标，则会将多个选定元素报告为绑定源列表中的元素。否则，将这些选定元素报告为列表模型中的对象。如果未选择任何内容，则该属性的值为空列表。 

|selectedElement_IGNORE_ADJUSTING |与 "selectedElement" 基本相同，但在更新列表选定内容时不通知更改。 

|selectedElements_IGNORE_ADJUSTING |与 "selectedElements" 基本相同，但在更新列表选定内容时不通知更改。 

|JTable |selectedElement |JTable 的选定元素；通知所有更改。如果在 JTableBinding 中将 JTable 作为目标，则会将选定元素报告为绑定源列表中的元素。否则，将选定元素报告为一个映射，其中，键由字符串 "column" 和列索引组成；值为该列的模型值。例如：{column0=column0value，column1=column1value，...} 如果未选择任何内容，则该属性的值为 ``空值`` 。 

|selectedElements |JTable 的选定元素的列表；通知所有更改。如果在 JTableBinding 中将 JTable 作为目标，则会将多个选定元素报告为绑定源列表中的元素。否则，将每个选定元素报告为一个映射，其中，键由字符串 "column" 和列索引组成；值为该列的模型值。例如：{column0=column0value, column1=column1value, ...} 如果未选择任何内容，则该属性的值为空列表。 

|selectedElement_IGNORE_ADJUSTING |与 "selectedElement" 基本相同，但在更新表选定内容时通知更改。 

|selectedElements_IGNORE_ADJUSTING |与 "selectedElements" 基本相同，但在更新表选定内容时不通知更改。 

|JTextComponent（包括其子类 JTextField、JTextArea 和 JEditorPane） |text |JTextComponent 的 text 属性；通知所有更改（包括键入内容）。 

|text_ON_FOCUS_LOST |JTextComponent 的 text 属性；仅在组件不处于焦点状态时通知更改。 

|text_ON_ACTION_OR_FOCUS_LOST |JTextComponent 的 text 属性；仅在组件通知 actionPerformed 或组件不处于焦点状态时通知更改。 
|===
link:/about/contact_form.html?to=3&subject=Feedback:%20Binding%20Beans%20and%20Data%20in%20Java%20Applications[+发送有关此教程的反馈意见+]



== 另请参见

* _使用 NetBeans IDE 开发应用程序_中的link:http://www.oracle.com/pls/topic/lookup?ctx=nb8000&id=NBDAG2649[+使用数据库应用程序和 Bean 绑定+]
* link:gui-functionality.html[+构建 GUI 应用程序简介+]
* link:http://java.net/projects/beansbinding/[+Beans 绑定 - Java.net+]
* link:http://docs.oracle.com/javase/tutorial/javabeans/index.html[+Java 教程的 JavaBeans(tm) 资源+]
* link:http://wiki.netbeans.org/NetBeansUserFAQ#GUI_Editor_.28Matisse.29[+GUI 编辑器常见问题解答+]
