文档

Java™教程
隐藏目录
使用JDBC与GUI API
导航: JDBC数据库访问
课程: JDBC基础知识

使用GUI API使用JDBC

示例CoffeesFrame.java演示了如何将JDBC与GUI API(特别是Swing API)集成。它在表格中显示了COFFEES数据库表的内容,并包含了字段和按钮,使您能够向表格中添加行。以下是这个示例的屏幕截图:

示例CoffeeFrames.java的屏幕截图

示例包含五个文本字段,对应于COFFEES表中的每个列。它还包含三个按钮:

这个示例(需要CoffeesTableModel.java)演示了将JDBC与Swing API集成的一般步骤:

  1. 实现TableModel接口
  2. 实现RowSetListener接口
  3. 布置Swing组件
  4. 为示例中的按钮添加监听器

实现javax.swing.event.TableModel

TableModel接口使Java Swing应用程序能够在JTable对象中管理数据。示例CoffeesTableModel.java实现了这个接口。它指定了JTable对象如何从RowSet对象中检索数据并在表格中显示。

注意:尽管这个示例在Swing应用程序中显示了COFFEES表的内容,但CoffeesTableModel类应适用于任何SQL表,只要它的数据可以用String对象表示。(然而,用于向COFFEES添加行的字段(在CoffeesFrame类中指定)对于其他SQL表需要进行修改。)

在实现TableModel接口的方法之前,CoffeeTableModel类的构造函数如下所示初始化了一些必要的成员变量:

public CoffeesTableModel(CachedRowSet rowSetArg)
    throws SQLException {

    this.coffeesRowSet = rowSetArg;
    this.metadata = this.coffeesRowSet.getMetaData();
    numcols = metadata.getColumnCount();

    // 获取行数
    this.coffeesRowSet.beforeFirst();
    this.numrows = 0;
    while (this.coffeesRowSet.next()) {
        this.numrows++;
    }
    this.coffeesRowSet.beforeFirst();
}

以下是在这个构造函数中初始化的成员变量的描述:

CoffeesTableModel.java示例实现了TableModel接口中的以下方法:

以下方法未实现,因为此示例不允许用户直接编辑表的内容:

实现getColumnCount和getRowCount

getColumnCountgetRowCount方法分别返回成员变量numcolsnumrows的值:

public int getColumnCount() {
    return numcols;
}

public int getRowCount() {
    return numrows;
}

实现getColumnClass

getColumnClass方法返回指定列的数据类型。为了简单起见,该方法返回String类,从而将表中的所有数据转换为String对象。JTable类使用该方法确定如何在GUI应用程序中渲染数据。

public Class getColumnClass(int column) {
    return String.class;
}

实现getColumnName

getColumnName方法返回指定列的名称。JTable类使用该方法为每个列添加标签。

public String getColumnName(int column) {
    try {
        return this.metadata.getColumnLabel(column + 1);
    } catch (SQLException e) {
        return e.toString();
    }
}

实现getColumnAt

getColumnAt方法从行集coffeesRowSet中检索指定行和列的值。JTable类使用该方法填充其表格。请注意,SQL从1开始对行和列进行编号,但TableModel接口从0开始;这就是为什么rowIndexcolumnIndex的值要加1的原因。

public Object getValueAt(int rowIndex, int columnIndex) {

    try {
        this.coffeesRowSet.absolute(rowIndex + 1);
        Object o = this.coffeesRowSet.getObject(columnIndex + 1);
        if (o == null)
            return null;
        else
            return o.toString();
    } catch (SQLException e) {
        return e.toString();
    }
}

实现isCellEditable

因为此示例不允许用户直接编辑表格的内容(行是通过另一个窗口控件添加的),所以无论rowIndexcolumnIndex的值如何,该方法都返回false

public boolean isCellEditable(int rowIndex, int columnIndex) {
    return false;
}

实现 javax.sql.RowSetListener

CoffeesFrame 只实现了接口 RowSetListener 中的一个方法,即 rowChanged。当用户向表中添加行时,将调用此方法。

public void rowChanged(RowSetEvent event) {

    CachedRowSet currentRowSet =
        this.myCoffeesTableModel.coffeesRowSet;

    try {
        currentRowSet.moveToCurrentRow();
        myCoffeesTableModel = new CoffeesTableModel(
            myCoffeesTableModel.getCoffeesRowSet());
        table.setModel(myCoffeesTableModel);

    } catch (SQLException ex) {

        JDBCTutorialUtilities.printSQLException(ex);

        // 在对话框中显示错误。

        JOptionPane.showMessageDialog(
            CoffeesFrame.this,
            new String[] {
                // 显示两行消息
                ex.getClass().getName() + ": ",
                ex.getMessage()
            }
        );
    }
}

此方法更新GUI应用程序中的表。

布置 Swing 组件

CoffeesFrame 的构造函数初始化并布置了 Swing 组件。以下语句检索 COFFEES 表的内容,将内容存储在 CachedRowSet 对象 myCachedRowSet 中,并初始化了 JTable Swing 组件:

CachedRowSet myCachedRowSet = getContentsOfCoffeesTable();
myCoffeesTableModel = new CoffeesTableModel(myCachedRowSet);
myCoffeesTableModel.addEventHandlersToRowSet(this);

// 显示表
table = new JTable(); 
table.setModel(myCoffeesTableModel);

正如之前提到的,此示例中使用的是 RowSet 对象(特别是 CachedRowSet 对象)来代表 COFFEES 表的内容,而不是 ResultSet 对象。

方法 CoffeesFrame.getContentsOfCoffeesTable 检索表 COFFEES 的内容。

方法 CoffeesTableModel.addEventHandlersToRowSet 向行集成员变量 CoffeesTableModel.coffeesRowSet 添加在 CoffeesFrame 类中定义的事件处理程序,即 rowChanged 方法。这使得类 CoffeesFrame 能够通知行集 coffeesRowSet 有关任何事件,特别是当用户点击“添加行到表格”、“更新数据库”或“放弃更改”按钮时。当行集 coffeesRowSet 收到这些更改通知时,将调用方法 CoffeesFrame.rowChanged

语句 table.setModel(myCoffeesTableModel) 指定使用 CoffeesTableModel 对象 myCoffeesTableModel 来填充 JTable Swing 组件 table

以下语句指定 CoffeesFrame 类使用布局 GridBagLayout 来布置其 Swing 组件:

Container contentPane = getContentPane();
contentPane.setComponentOrientation(
    ComponentOrientation.LEFT_TO_RIGHT);
contentPane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();

详细了解如何使用布局 GridBagLayout 的信息,请参见 如何使用 GridBagLayout使用 JFC/Swing 创建 GUI 中。

查看源代码 CoffeesFrame.java 以查看如何将此示例的 Swing 组件添加到布局 GridBagLayout 中。

为按钮添加监听器

以下语句为按钮 Add row to table 添加监听器:

button_ADD_ROW.addActionListener(
    new ActionListener() {
      
    public void actionPerformed(ActionEvent e) {

        JOptionPane.showMessageDialog(
            CoffeesFrame.this, new String[] {
                "正在添加以下行:",
                "咖啡名称:[" +
                textField_COF_NAME.getText() +
                "]",
                "供应商 ID:[" +
                textField_SUP_ID.getText() + "]",
                "价格:[" +
                textField_PRICE.getText() + "]",
                "销售量:[" +
                textField_SALES.getText() + "]",
                "总量:[" +
                textField_TOTAL.getText() + "]"
            }
        );

        try {
            myCoffeesTableModel.insertRow(
                textField_COF_NAME.getText(),
                Integer.parseInt(textField_SUP_ID.getText().trim()),
                Float.parseFloat(textField_PRICE.getText().trim()),
                Integer.parseInt(textField_SALES.getText().trim()),
                Integer.parseInt(textField_TOTAL.getText().trim())
            );
        } catch (SQLException sqle) {
            displaySQLExceptionDialog(sqle);
        }
    }
});

当用户点击此按钮时,它执行以下操作:

如果抛出SQLException,则方法CoffeesFrame.displaySQLExceptionDialog创建一个消息对话框,显示SQLException的内容。

以下语句将监听器添加到按钮更新数据库

button_UPDATE_DATABASE.addActionListener(
    new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            try {
                myCoffeesTableModel.coffeesRowSet.acceptChanges();
                msgline.setText("已更新数据库");
            } catch (SQLException sqle) {
                displaySQLExceptionDialog(sqle);
                // 现在撤销更改
                try {
                    createNewTableModel();
                    msgline.setText("已放弃更改");
                } catch (SQLException sqle2) {
                    displaySQLExceptionDialog(sqle2);
                }
            }
        }
    }
);

当用户点击此按钮时,表COFFEES将使用myCoffeesTableModel.coffeesRowSet的内容进行更新。

以下语句将监听器添加到按钮放弃更改

button_DISCARD_CHANGES.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        try {
            createNewTableModel();
        } catch (SQLException sqle) {
            displaySQLExceptionDialog(sqle);
        }
    }
});

当用户点击此按钮时,将调用方法CoffeesFrame.createNewTableModel,该方法将用COFFEES表的内容重新填充JTable组件。


上一页: 使用存储过程
下一页: 结束