在一段时间内调用JComboBox#addItem()(resultSet.next())循环最终只有1个项目

时间:2011-06-17 00:29:05

标签: java swing jdbc

这是给我提问的代码。

try{
ResultSet rs = Main.dbase.search("select * from myTable");
//rs.next()
while(rs.next())
{
 cmb.addItem(rs.getString(1).trim());
}
rs.close();
} catch (Exception ex) {System.out.println(ex);}

这里dbase是一个执行Statement.executeQuery的对象,而cmb是JComboBox。

问题是即使表有10行,我只能在cmb中获得单行。 如果我没有注释掉第一个 rs.next(),我会在cmb中获得第二行。

我试图跟踪 rs.next()的值,发现在 while(rs.next())之后,它总是给出false。

我的目标是获取cmb中的所有10个值。 就像我研究过的那样,这段代码应该将所有值都添加到cmb中,但只添加一个值。 如果在进入循环之前我调用了 rs.next(),则下一个值会添加到cmb。

3 个答案:

答案 0 :(得分:2)

您没有提及catch阻止是否有任何异常。

我看到的可能会阻止循环比第一行更进一步,可能是下一行有NULL第一列。

实际上,如果NULL返回的任何行的第一列中有"select * from myTable",那么rs.getString(1).trim()会抛出一个NullPointerException来中断循环

你可以通过写:

来避免这种情况
try {
    ResultSet rs = Main.dbase.search("select * from myTable"); 
    while(rs.next()) {
        String result = rs.getString(1);
        if (result != null) {
            result = result.trim();
        }
        cmb.addItem(result);
    } 
    rs.close();
} catch (Exception ex) {
    System.out.println(ex);
} 

此外,我会改进整个片段以便:

  • 确保rs即使发生异常也会关闭
  • 确保我们看到任何异常的完整堆栈跟踪
  • 确保cmb仅从EDT(Swing EDT规则)
  • 更新
  • 通过汇总所有addItems
  • 来避免对EDT的过多调用

然后这就是你想要的:

ResultSet rs = null; 
try {
    final List<String> allItems = new ArrayList>String>();
    rs = Main.dbase.search("select * from myTable"); 
    while(rs.next()) {
        String result = rs.getString(1);
        if (result != null) {
            result = result.trim();
        }
        allItems.add(result);
    }
    SwingUtilities.invokeLater(new Runnable() {
        @Overrive public run() {
            for (String item: allItems) {
                cmb.addItem(item);
            }
        }
    });
} catch (Exception ex) {
    ex.printStacktrace();
} finally {
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

当然,某些部分仍然可以进一步改进,例如,如果它不是ResultSet,我可能会编写一个帮助方法来关闭null,因为这个代码可能会在很多部分重用地方。

答案 1 :(得分:1)

如果您的ResultSet实际填充正确,则问题出在Swing上。也就是说,Swing不是线程安全的。将项目添加到JComboBox时,在事件发送线程或EDT中执行此操作至关重要。为此,请使用SwingUtilities实用程序类在Runnable上的EventQueue上发布EDT任务。例如,

while(rs.next()){
    if(SwingUtilities.isEventDispatchThread()){
        cmb.addItem(rs.getString(1).trim());
    }
    else{
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run(){
                cmb.addItem(rs.getString(1).trim());
            }
        });
    }
}

无论实际上最终是什么问题,请注意这个建议。

答案 2 :(得分:0)

这是你正在做的事情的正确结构,所以问题可能在其他地方。 SELECT *在这种情况下不是一个好主意,而SELECT *rs.getString(1)结合使我们无法再猜测添加到组合框中的内容。我猜第一栏不是你想的那样。至少,使用rs.getString("column_name_I_want")

顺便说一下,您确定要search而不是某种execute吗?