我正在做一个学校项目,我无法将结果集中的数据存储在JTable中。以前我用过DButils,但现在我想知道是否有办法做同样的事情,而不必使用外部类文件,或者如果它更容易使用DButils。如何使用JTable中Resultset的使用数据?
数据仅来自一个表,所有需要发生的数据都必须显示在JTable中。
我会在这里发布我的代码,但我看了,我能找到的唯一教程是关于如何使用和Object [] []填充JTable的教程。我正在使用JDBC来创建连接。
在此先感谢。
我正在做一个学校项目,我无法将结果集中的数据存储在JTable中。以前我用过DButils,但现在我想知道是否有办法做同样的事情,而不必使用外部类文件,或者如果它更容易使用DButils。如何使用JTable中Resultset的使用数据?
数据仅来自一个表,所有需要发生的数据都必须显示在JTable中。
我会在这里发布我的代码,但我看了,我能找到的唯一教程是关于如何使用和Object [] []填充JTable的教程。我正在使用JDBC来创建连接。
在此先感谢。
当然有一种方法:遍历ResultSet
并将您发现的内容添加到传递到JTable
的Object [][]
数组中。对于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;
}
嗯,这将需要几个步骤。
我会解释一下我的方式,这对于很大的套件很有用,但是如果您只想显示几行,则会有点复杂。不过,我相信它会帮助你。这种方法将在飞行中加载所需的记录,而不是全部加载。它创造了整套的幻觉,但无需等待长时间的负载。
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
好,希望帮助.--
对'AbstractTableModel'+1,也显示[这里](http://stackoverflow.com/a/9134371/230513)。你可以使用更窄的'fireXxx()'方法。 – trashgod 2012-07-12 18:27:06
你可以作为样品使用:http://technojeeves.com/joomla/index.php/free/59-resultset-to-tablemodel – 2012-07-11 12:21:06