2012-07-11 33 views
0

我正在做一个学校项目,我无法将结果集中的数据存储在JTable中。以前我用过DButils,但现在我想知道是否有办法做同样的事情,而不必使用外部类文件,或者如果它更容易使用DButils。如何使用JTable中Resultset的使用数据?

数据仅来自一个表,所有需要发生的数据都必须显示在JTable中。

我会在这里发布我的代码,但我看了,我能找到的唯一教程是关于如何使用和Object [] []填充JTable的教程。我正在使用JDBC来创建连接。

在此先感谢。

+0

你可以作为样品使用:http://technojeeves.com/joomla/index.php/free/59-resultset-to-tablemodel – 2012-07-11 12:21:06

回答

1

当然有一种方法:遍历ResultSet并将您发现的内容添加到传递到JTableObject [][]数组中。对于ResultSet中的每一行,二维数组中有一行;列是值。

你会遇到的问题是,你不知道有多少行没有迭代就回来了。这就是为什么将它加载到Map<String, Object>可能是一个更好的主意。

下面是显示如何操作的示例。你会发现在我回答这个方法(及以上)对这个问题:

java sql connections via class

public static List<Map<String, Object>> map(ResultSet rs) throws SQLException { 
    List<Map<String, Object>> results = new ArrayList<Map<String, Object>>(); 
    try { 
     if (rs != null) { 
      ResultSetMetaData meta = rs.getMetaData(); 
      int numColumns = meta.getColumnCount(); 
      while (rs.next()) { 
       Map<String, Object> row = new HashMap<String, Object>(); 
       for (int i = 1; i <= numColumns; ++i) { 
        String name = meta.getColumnName(i); 
        Object value = rs.getObject(i); 
        row.put(name, value); 
       } 
       results.add(row); 
      } 
     } 
    } finally { 
     close(rs); 
    } 
    return results; 
} 
+0

你可以给我一个代码示例或简单的英语解释吗? (我真的不明白) – AceFire6 2012-07-11 19:38:06

+0

如何遍历'ResultSet'的例子已经广泛使用。这[示例](http://stackoverflow.com/a/9134371/230513)显示了如何在'Map'周围创建'TableModel'。 – trashgod 2012-07-12 18:23:11

1

嗯,这将需要几个步骤。

我会解释一下我的方式,这对于很大的套件很有用,但是如果您只想显示几行,则会有点复杂。不过,我相信它会帮助你。这种方法将在飞行中加载所需的记录,而不是全部加载。它创造了整套的幻觉,但无需等待长时间的负载。

1)好吧,首先,让我们假设我们有一个很好的JFrame,您可以显示,首先。所以首先我将添加一个JScrollPane,并在其中添加一个JTable。运行它,并确保在滚动条内部有一个空JTable的好窗口。

2)所以接下来你需要一个JTable的数据源。由于JTable是一个非专用于SQL resultSets的通用组件,因此它需要一个实现javax.swing.table.AbstractTableModel的数据源,该数据源与SQL无关。所以我们现在创建一个TableModelClass来实现AbstractTableModel,然后我们将这个添加到JTable中,它将开始工作。当然,诀窍是通过使用我们的SQL结果集来实现所有的AbstractTableModel方法来获取数据,这取决于您。从这里我的建议 - >

3)由于这是动态的,我们不需要加载所有的数据,但我们需要一个初始设置来显示。我会有一个固定大小的对象[] [],可以说200 - 300行。所以我将首先执行SQL并填充200-300行缓冲区大小的数组。要缓存多少取决于两件事情:1它应该足以获得JTable当前显示大小的所有数据,并且2应该足够小,以便当我们滚动并获得后续缓存时,它将非常快速地执行。

4)现在让我们开始实现所有AbstractTableModel的接口方法。

5)首先我们看一下初始结果集并报告列数。只需添加一个类变量,设置列数并使用它返回:public int getColumnCount()。这从现在起不会改变。

6)还要查看结果集元数据,在类中创建一个列表变量并添加元数据中返回的列名称。使用此列表将返回“getColumnName(int col)”中的列名称。当然,col索引是结果集中的列位置。

7)现在让我们做“int getRowCount()”。在TableModelClass中保留一个变量来包含rowCount,并以此方法返回它。提示:现在不要担心,将其设置为65000这样的固定大数字,这会让您在动态加载记录时进行滚动。一旦我们达到最后,我们会将数字设置为真实值,滚动窗格将调整到正确的比例。相信我,它工作正常。

8)现在来了有趣的一部分。由于JTable呈现表格的第一个“页面”,并且在用户滚动时它将开始调用“getValueAt(int row,int col)”。这将直接映射到我们的Object [] [],但由于我们只有一个缓存,而不是整个表,所以当用户向下滚动时,我们需要获取更多数据。我这样做:

public Object getValueAt(int row, int col) 
    { 
     // load failed before, no more trying... 
     if(loadExceptionOccur || (row >= visualTableSize)) return(""); 

     // check if requested row is OUT of cache … 
     try{    
     if( 
      // less than cache lower limit... 
      ((row < startRow) 
      || 
      // Beyond cache upper limit... 
      (row >= startRow + tableDataCache.size())) 
         // Stop unnecessary loading, because of Jtable readjusting 
         // its visual table size and redrawing the entire table. 
         && !tableRedraw 

     // yes, get new cache... 
     ){ 
      load(row); // <- below is code 
     } 

      // now we now the row is in cache, so -> 

      // verify requested cell in cache, or beyond data rows, 
      if( 
        // greater than lower limit 
        (row >= startRow) 
        && 
        // less than upper limit... 
        (row < (startRow + tableDataCache.size())) 
      ){ 
        tableRedraw = false; 

      // just get the data from the cache. tableDataCache is just your Object[][] array… 
        Object cellValue = ((recordClass) tableDataCache.get(row-startRow)).getValueAt(col); 


        return (cellValue); 
      } 
      else{ 
        // just show as blank 
        return("");    
      }     
     } 
     catch(Exception error ){ 



    … 

如果缓存未命中,您需要重新加载缓存数据。我通常会在请求行之前加载一些行,并且至少在一个JTable页面大小之前加载一些行,这样我们只需要一次到db来渲染一个屏幕。加载之前,缓存越大,滚动越多,但加载缓存所用的时间越长。如果您调整它,缓存处理可能几乎不明显。

这里是“负载”的实现:

public void load(int rowIndex) 
    throws KExceptionClass 
    { 
     // calculate start of new cache, if not enough rows for top half of cache 
     // then start from 0 
     int halfCache = cacheSize/2 ; 
     int DBStartRow = 0;  
     if(rowIndex > halfCache) DBStartRow = rowIndex - halfCache; 

     //Do query to DB 
     try{ 

      SQLP.load(DBStartRow, cacheSize); // <- using jdbc load from DbsartRow as many rows as cacheSize. Some sample SQL paging code below -> 

     }catch(Exception loadError){ 

      // if the database fails or something do this, so you don’t get a billion errors for each cell. -> 

      //set load failed flag, kill window       
      loadExceptionOccur = true;   
      visualTableSize = 0; 
      tableDataCache = new ArrayList<recordClass>();   
      fireTableDataChanged(); // clear the Jtable 

      // log error 
      log.log(this, KMetaUtilsClass.getStackTrace(loadError)); 
      // show error message 
      throw new KExceptionClass("Could not load table data! " , loadError); 

     } 

     //Load rows into the cache list. 
     //Key field values are in the cache list as the last field in each record. 
     tableDataCache.clear();  // the Object [][], wrapped in class 

     while(SQLPreprocessor.nextRowValue()) { 

      SQL.fetch(record);    //<- get JDBC rows to table cache 
      tableDataCache.add(record); // this uses my library, change to JDBC or what ever you use to access SQL 
     } 

     log.log(this, "cacheList size = " + tableDataCache.size()); 

     //--------- 

     if( 
      // Last requested row number   
      (DBStartRow + cacheSize) > 
      // Last replied row number 
      (SQLPreprocessor.getloadedStartRowIndex() + SQLPreprocessor.getloadedRowCount()) 
      ){ 
       // It is the end of table. 
       // The visual table is readjusted accordingly. 
       visualTableSize = SQLPreprocessor.getloadedStartRowIndex() + SQLPreprocessor.getloadedRowCount(); 
       fireTableDataChanged(); 
       tableRedraw = true; 
      } 

     startRow = SQLPreprocessor.getloadedStartRowIndex();       


     log.log(this, "visualTableSize = " + visualTableSize); 

    } 

确定这将动态地加载在小高速缓存中的数据,这将得到具有整套的印象。 如果用户滚动到中间或一直到最后,JTable将只询问数据需要在移动时不显示所有行,因此,如果您有一个10K的行表,但JTable只是20行高,滚动到结束将只需要40-50行加载。很不错。您的用户会留下深刻的印象。

现在的事情是,负载假定您有一个SQL游标,它按行号向前和向后移动。这个简单的事情在SQL中是一个相当大的挑战。对于Oracle检查:http://www.oracle.com/technetwork/issue-archive/2006/06-sep/o56asktom-086197.html

好,希望帮助.--

+0

对'AbstractTableModel'+1,也显示[这里](http://stackoverflow.com/a/9134371/230513)。你可以使用更窄的'fireXxx()'方法。 – trashgod 2012-07-12 18:27:06

相关问题