我正在做一个学校项目,我遇到了将结果集中的数据存储在JTable中的问题。以前我使用过DButils,但现在我想知道是否有办法在不使用外部类文件或更容易使用DButils的情况下做同样的事情。
数据仅来自一个表,所有需要发生的事情是数据必须显示在JTable中。
我会在这里发布我的代码,但我已经查看了,我能找到的唯一教程是关于如何使用和Object [] []填充JTable的。我正在使用JDBC来创建连接。
提前致谢。
答案 0 :(得分:1)
当然有一种方法:遍历ResultSet
并将您找到的内容添加到传递给Object [][]
的{{1}}数组中。在JTable
中每行的2D数组中有一行;列是值。
你遇到的问题是你不会知道有多少行没有迭代它。这就是为什么将它加载到ResultSet
可能是一个更好的主意。
这是一个展示如何操作的示例。你会在这个问题的答案中找到这种方法(以及更多):
java sql connections via class
Map<String, Object>
答案 1 :(得分:1)
这需要几个步骤。
我将解释我的方式,这对于非常大的集合是有益的,但是如果你只想显示几行则有点复杂。我仍然相信它会对你有所帮助。此方法将动态加载所需的记录,而不是整个装置。它创造了拥有整套装置的错觉,但不必等待长时间的装载。
1)好的,首先,让我们假设我们有一个很好的JFrame,你可以开始显示。所以首先我要添加一个JScrollPane,在里面我将添加一个JTable。运行它并确保你有一个漂亮的窗口,里面有一个空的JTable滚动条。
2)接下来你需要一个JTable的数据源。由于JTable是非专门用于SQL resultSets的非常通用的组件,因此它需要一个实现与SQL无关的javax.swing.table.AbstractTableModel的数据源。所以我们现在将创建一个将实现AbstractTableModel的TableModelClass,然后我们将它添加到JTable中,它将开始工作。当然,诀窍是实现所有使用我们的SQL结果集获取数据的AbstractTableModel方法,这取决于您。从这里是我的建议 - &gt;
3)由于这将是动态的,我们不需要预先加载所有数据,但我们需要一个初始设置来显示。我将有一个固定大小的Object [] [],比方说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
好的,希望有所帮助.--