ResultSet填充JTable列名但不填充数据

时间:2014-01-16 00:07:05

标签: java mysql swing prepared-statement resultset

注意:这不是重复,我已经签出:I can't get my JTable to show anythingI get the Jtable but no data

虽然这些问题看起来非常相似,但它们与我所遇到的问题并不相同。让我解释一下:

我有一个GUI,其中有几个JTable从MySQL数据库中填充。在我的初始GUI上,表格工作正常。但是,有一次我将用户带到一个新的JFrame。在此框架上,由于某种原因,表格显示并填充了列名称,但没有数据。我不能为我的生活找出原因。

以下是我的第一个GUI中的代码:

 iTable = new JTable(writeItemResult(res4));
 iTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
 iTable.getColumnModel().getColumn(0).setPreferredWidth(27);
 iTable.getColumnModel().getColumn(1).setPreferredWidth(375);
 iTable.getColumnModel().getColumn(2).setPreferredWidth(150);
 iTable.getColumnModel().getColumn(0).setResizable(false);
 sorter = new TableRowSorter<TableModel>(iTable.getModel());
 iTable.setRowSorter(sorter);

 JScrollPane scrollpane3 = new JScrollPane(iTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
 scrollpane3.setPreferredSize(new Dimension(500, 150));
 c.fill = GridBagConstraints.HORIZONTAL;
 c.gridx = 0;
 c.gridy = 16;
 c.gridwidth = 6;
 pane.add(scrollpane3, c);

我的writeItemResult方法:

public static DefaultTableModel writeItemResult (ResultSet res4) throws SQLException {

    ResultSetMetaData metaData = res4.getMetaData();

    Vector<String> columnNames = new Vector<String>();
    int columnCount = metaData.getColumnCount();
    for (int column = 1; column <= columnCount; column++) {
        columnNames.add(metaData.getColumnName(column));
    }

    Vector<Vector<Object>> data = new Vector<Vector<Object>>();
    while (res4.next()) {
        Vector<Object> vector = new Vector<Object>();
        for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
            vector.add(res4.getObject(columnIndex));
        }
        data.add(vector);
    }
    return new DefaultTableModel(data, columnNames);
}

我的res4结果集:

statement2 = connect.createStatement();
res4 = statement2.executeQuery("SELECT id, prompt, type FROM items ORDER BY prompt");

所以,正如我所说,上面的代码WORKS对我的第一个JFrame很好。我的第一个JFrame的整个代码太大了,所以除非特别要求,否则我不会费心去粘贴它。

以下是我的第二个JFrame的完整代码,正如我所说,返回表和列名但没有数据:

} if (e.getSource() == design) {
        int str = fTable.getSelectedRow();
        int stc = fTable.getSelectedColumn();

        if (stc != 0) {
            JOptionPane.showMessageDialog(null, "Error: Please click the Form ID of the form you wish to modify.", "Error!", JOptionPane.ERROR_MESSAGE);
            return;
        }  

         selObj = (Object) fTable.getModel().getValueAt(str, stc);

         try {
            p_statement6.setString(1, selObj.toString());
            res6 = p_statement6.executeQuery();
        } catch (SQLException e1) {
            e1.printStackTrace();
        }

         try {
            while (res6.next()){
                    formID1 = res6.getString("id");
                    formName1 = res6.getString("title");
                }
        } catch (SQLException e1) {
            e1.printStackTrace();
        }

         int width = 900;
         int height = 900;
         designForm = new JFrame("Designer");
         designForm.setSize(width,height);


         pane = designForm.getContentPane();
         pane.setLayout(new GridBagLayout());
            GridBagConstraints c = new GridBagConstraints();

            if (shouldFill) {
                //natural height, maximum width
                c.fill = GridBagConstraints.HORIZONTAL;
            }

         des_name = new JLabel("<html><small>Designing: "+formName1+"</small></html>");
         c.fill = GridBagConstraints.HORIZONTAL;
         c.gridx = 0;
         c.gridy = 0;
         c.gridwidth = 1;
         pane.add(des_name, c); 

         test = new JButton("Test");
         c.gridx = 0;
         c.gridy = 1;
         c.gridwidth = 1;
         pane.add(test, c);
         test.addActionListener(this);

         designForm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         Dimension sD = Toolkit.getDefaultToolkit().getScreenSize();
         designForm.setLocation((sD.width - width)/2, (sD.height-height)/2);
         designForm.setResizable(true);
         designForm.setVisible(true);

  } if (e.getSource() == test) {
      try {
             iTable = new JTable(writeItemResult(res4));
             iTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
             iTable.getColumnModel().getColumn(0).setPreferredWidth(27);
             iTable.getColumnModel().getColumn(1).setPreferredWidth(330);
             iTable.getColumnModel().getColumn(2).setPreferredWidth(140);
             iTable.getColumnModel().getColumn(0).setResizable(false);
             sorter = new TableRowSorter<TableModel>(iTable.getModel());
             iTable.setRowSorter(sorter);

             JScrollPane scrollpane4 = new JScrollPane(iTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
             scrollpane4.setPreferredSize(new Dimension(500, 150));

             JOptionPane.showMessageDialog(null, scrollpane4);

  } catch (Exception e1) {
      e1.printStackTrace();
  }
  }

如果你很好奇,p_statement6是:

p_statement6 = connect.prepareStatement("SELECT * from checklists where id = ?");

顺便说一句,我没有错误。

破桌图片: broken

工作表图片:working

所以,这就是我觉得适用的一切。如果您需要更多信息,请随时提出。

解决方案

感谢@peeskillet,我的问题的解决方案很简单:我试图使用一个耗尽的结果集。只需设置结果集Scroll_Insensitive和Concur_Updatable,问题就解决了。

3 个答案:

答案 0 :(得分:1)

下面:

int str = fTable.getSelectedRow();
int stc = fTable.getSelectedColumn();

...

selObj = (Object) fTable.getModel().getValueAt(str, stc); // wrong indexes!!

这些索引属于 视图 。如果您想从表模型中获取值,则需要将它们转换为各自的 模型 索引:

selObj = fTable.getModel().getValueAt(fTable.convertRowIndexToModel(str), fTable.convertColumnIndexToModel(stc));

或者您可以直接从表中获得正确的选定值:

selObj = fTable.getValueAt(str, stc);

由于selObj.toString()是查询参数,错误的值可能会导致空ResultSet。因此,表格不会被填充。

请参阅:


修改

我也会检查一下:

p_statement6 = connect.prepareStatement("SELECT * from checklists where id = ?");
p_statement6.setString(1, selObj.toString()); // is id a VARCHAR or is NUMERIC?

你说你这里没有任何错误,但是准备好的文章将被解析为:

SELECT * from checklists where id = '1';

如果id列是VARCHAR,那么没关系,但如果它是某种数字类型,那么你可能会获得SQLException

如果是这种情况,那么您需要将selObj转换为Integer并使用PreparedStatement.setInt(index, value)代替setString()

p_statement6.setInt(1, (Integer)selObj);

答案 1 :(得分:1)

您似乎尝试对两个表使用相同的ResultSet

 new JTable(writeItemResult(res4));

这两个表都使用res4。这样做的问题是,第一个工作正常,但它会耗尽ResultSet的数据。数据已经完成。因此,在第二个rs.next()中尝试writeItemResult(res4)只能返回列标题,因为这只是元数据

  

默认的ResultSet对象不可更新,并且只有一个向前移动的游标。因此,您只能迭代一次,并且只能从第一行到最后一行。可以生成可滚动和/或可更新的ResultSet对象。以下代码片段(其中con是有效的Connection对象)说明了如何使结果集可滚动且对其他人的更新不敏感,并且可以更新。

   Statement stmt = con.createStatement(
                                  ResultSet.TYPE_SCROLL_INSENSITIVE,
                                  ResultSet.CONCUR_UPDATABLE);
   ResultSet rs = stmt.executeQuery("SELECT a, b FROM TABLE2");
   // rs will be scrollable, will not show changes made by others,
   // and will be updatable
  • static final int TYPE_SCROLL_INSENSITIVE - 指示ResultSet对象类型的常量,该对象可滚动但通常对对ResultSet构成的数据的更改不敏感。
  • static final int CONCUR_READ_ONLY - 表示可能无法更新的ResultSet对象的并发模式的常量。

因此,您必须执行上述操作才能使ResultSet可滚动。然后你需要使用

  • void beforeFirst() throws SQLException - 将光标移动到此ResultSet对象的前面,就在第一行之前。如果结果集不包含任何行,则此方法无效。

因此,如果您只是将res4.beforeFirst()放在writeItemResult()中,它也适用于第二张表格。


另外,在旁注中,如果您希望表使用相同的数据,为什么不让它们共享相同的TableModel

table2.setModel(table1.getModel());

答案 2 :(得分:0)

替换

selObj = (Object) fTable.getModel().getValueAt(str, stc);

通过

selObj = (Object) fTable.getValueAt(str, stc);

iTable = new JTable(writeItemResult(res4));

通过

iTable = new JTable(writeItemResult(res6));