Está en la página 1de 11

JTABLE, TABLEMODEL Y RENDIMIENTO

Francesc Ross / lulio 2004


Con frecuencia nos vemos obligados a visualizar una gran cantidad de datos mediante una
JTable. El resultado es una carga lenta, un scroll penoso y un consumo de RAM intolerable.
Ciertamente, hay alternativas. Uno siempre intenta minimizar los datos que carga e incluso se
inventa algn tipo de cach! que necesita un mont"n de pruebas hasta que se da por aceptable.
#a mayor parte de los datos en las cargas masivas suelen tener su origen en una base de datos a la
que accedemos mediante un driver $%&C. En este art'culo hago una propuesta de un uso racional
tanto del TableModel como de las posibilidades que nos ofrece $%&C (.) *y posteriores+ para
reducir a pr,cticamente nada el coste de la representaci"n de grandes volmenes de datos
mediante JTables.
!"# $A%EMO& MAL'
Antes de e-poner mi propuesta creo que es conveniente analizar algunas de las acciones m,s
frecuentes que nos llevan a la ineficiencia.
"sar lo (ue )a es*+ ,ec,o
&ien, .usar lo que ya est, hecho/ no es malo si lo que est, hecho funciona como es debido. Este no
es el caso, por e0emplo, de una de las clases .ya hechas/ de JTableModel1
DefaultTableModel. #os m,s comodones nos limitamos a usarla directamente, y los que lo son
menos, se permiten subclasearla. 2in embargo, %efault3ableModel es el final de una cadena de dos
elementos1 la interficie JTableModel y la clase abstracta que la implementa1
AbstractTableModel. #a clase DefaultTableModel no es m,s que una soluci"n de
compromiso que nos ofrece 2un. 4o dir'a que, en realidad, es tan solo un e0emplo pr,ctico, m,s o
menos afortunado.
No leer con -e*alle las A.Is (ue *ocan
En realidad, nuestra primera apro-imaci"n se basaba en un .copy5paste/ del c"digo de un
compa6ero que en cinco minutos, mientras tom,bamos un caf!, nos cont" que eso de las tablas y el
$%&C era muy sencillito, pero que el Swing, ya se sabe, es m,s lento que el caballo del malo.
En definitiva, sin ver un Javadoc ni por el forro, nos hemos lanzado a escribir nuestra primera
versi"n de la aplicaci"n.
7s invito a hacer una prueba. 8reguntad a vuestros compa6eros *y a vosotros mismos, claro est,+ si
tienen una bookmark de las A89s de $ava en su e-plorador. :er!is qu! poquitos la tienen.
.OR !"# E&T/ MAL LO !"E $A%EMO&'
"sar lo (ue )a es*+ ,ec,o0 De1aul*Ta2leMo-el
#a clase DefaultTableModel e-tiende AbstractTableModel y, si bien para algunos casos
simples y con poco volumen de datos puede ser til, tiene varios problemas. El primero es el uso
; de ;;
e-haustivo de la clase Vector. <o entraremos en detalles, s"lo decir que Vector tiene todos sus
m!todos sincronizados lo que es bastante caro y, en la mayor parte de los casos, innecesario. 2er'a
m,s conveniente usar una ArrayList para el almacenamiento de datos. Es equivalente a Vector,
pero no tiene sus m!todos sincronizados.
8ara aquellos casos simples en los que puede ser interesante usar un modelo con las funcionalidades
de DefaultTableModel, he desarrollado un nuevo modelo con la misma funcionalidad que
DefaultTableModel pero basado en una ArrayList1 ArrayListTableModel.
2i bien ArrayListTableModel da un mayor rendimiento que DefaultTableModel *un
(=> apro-imadamente+, no es la panacea. #as pruebas se han realizado con una tabla de ?@.A;B
registros que ocupa, apro-imadamente, C,;? M&. Esto significa que, en ambos casos hemos de tener
cargados en RAM una List de, al menos, C,;? M&.
&ueno, hemos conseguido me0orar el rendimiento, pero no los requisitos de memoria.
No leer con -e*alle las A.Is (ue *ocan
2! que no se puede leer todo con detalle, pero es conveniente dar una leidita a los Javadoc de las
A89s involucradas en nuestro problema y al menos mantener pointers a lo que nos ha parecido
interesante *aunque no le hayamos visto una aplicaci"n inmediata+.
DEu! A89s est,n involucradas en nuestro problemaF &,sicamente, nueve1
javax.swing.JTable
javax.swing.table.JTableModel
javax.swing.table.AbtractTableModel
javax.swing.table.TableCellRenderer
java.sql.Connection
java.sql.DatabaseMetaData
java.sql.tate!ent
java.sql.Resultet
java.sql.ResultetMetaData
3odas aparecen en la soluci"n propuesta y comentaremos con m,s detalle, en su momento, los
aspectos que nos interesan de cada una de ellas.
&OL"%I3N %ON Arra)Lis*
2e recomienda utilizar ArrayList en vez de Vector siempre que podamos. 3ened en cuenta
que Vector e-iste desde el $%G ;.) mientras que ArrayList aparece en $%G ;.(. Algo debe
aportar...
Hemos comentado que el factor determinante es que ArrayList no tiene m!todos
sync"roni#ed. Esto implica que si otro thread modifica nuestra ArrayList, hay que hacer la
sincronizaci"n a mano. 2i consideramos que este hecho no es importante para nuestra aplicaci"n, y
creo que en el B)> de los casos de modelos de JTable no lo es, podemos usar un modelo basado
en ArrayLists en nuestro modelo, 2i lo es, podemos seguir usando el consabido
DefaultTableModel.
( de ;;
El problema es que 2un no proporciona ningn modelo basado en ArrayList y nos tocar,
escribirlo desde cero. 4o he escrito un nuevo modelo basado en ArrayList,
ArrayListTableModel, que se supone que debe funcionar e-actamente igual que
DefaultTableModel y lo pongo a vuestra disposici"n. Mis pruebas de rendimiento, como he
comentado m,s arriba, me dan un (=> de me0ora de rendimiento respecto a
DefaultTableModel. Recordad, sin embargo, que nadie nos quita el hecho de tener todos los
registros en RAM.
Como es l"gico, ArrayListTableModel e-tiende AbstractTableModel. 2i ten!is que
escribir vuestro propio modelo, e-tended siempre AbstractTableModel, no e-tend,is
DefaultTableModel.
&OL"%I3N %ON JDB% Y &%ROLLABLE %"R&OR&
Esta es, para m', la soluci"n "ptima ya que cumple con los dos requisitos fundamentales1
;. Me0ora el rendimiento
(. Utiliza poca memoria
#a soluci"n que propongo es sencilla de implementar y, adem,s, muy eficiente. 8odr'a limitarme a
e-plicar someramente su implementaci"n y dar el c"digo, pero como no creo que sea una soluci"n
definitiva y es posible que a m,s de uno se le ocurra algo me0or, escribir! un poco m,s e intentar!
e-plicar c"mo usa JTable los TableModel.
Es evidente que la soluci"n propuesta no es la panacea. Como ver!is el traba0o lo hace el gestor de
bases de datos, lo que supone una cone-i"n abierta con la base de datos mientras se est! e0ecutando
nuestra aplicaci"n y una carga para el servidor.
El 4ara-i56a M7% 8Mo-el 7ie9 %on*roller:
Creo que todos sab!is m,s o menos c"mo funciona este paradigma, as' que no entrar! en detalles
introductorios y me centrar! en lo que nos interesa, simplificando *hasta la incorrecci"n+ lo que sea
necesario.
Swing no utiliza e-actamente el M:C, sino una variante1 M% *Model Delegate+ en la que el
Delegate incluye View y Controller. Adem,s, JTable es un componente que est, formado por
varios subcomponentes y cada uno de ellos con su modelo y su delegate.
JTa2le ) M7%0 un e;e64lo sencillo
2implificando mucho, diremos que una JTable muestra unos datos que se encuentran en el
modelo. Una JTable tiene unas dimensiones determinadas en las que .caben/ un nmero concreto
de registros mostrables. JTable lo sabe y le pide al modelo s"lo aquellos registros que puede
mostrar. En la mayor parte de los casos, nuestras JTables se encontrar,n dentro de un
Jcroll$ane ya que no disponemos de espacio suficiente para mostrar todos los registros. Cada
vez que, por e0emplo, movemos la barra de desplazamiento vertical del Jcroll$ane, nuestra
JTable le pide m,s datos al modelo para poderlos mostrar. #a soluci"n es "ptima ya que s"lo le
pide unos pocos datos1 aqu!llos que puede representar. El m!todo que utiliza para pedir datos al
modelo es getValueAt%int row' int colu!n(.
9maginemos que tenemos una JTable con dos columnasI la primera muestra los nmeros de ) a
)** y la segunda, su doble *el valor de la primera columna, multiplicado por dos+. Una utilizaci"n
C de ;;
no recomendable de nuestro modelo mantendr'a una matriz con los valores de los ;)) primeros
nmeros y su doble1
int+,+, data - new int+)**,+.,/
+...,
0rivate void fillData%( 1
for %int i - )/ i 2- )**/ i33( 1
data+i4),+*, - i/
data+i4),+), - i 5 ./
6
6
En nuestro modelo, declaramos una matriz de enteros de )**x. y la llenamos mediante el m!todo
fillData%(.
8ara pedir datos a nuestro modelo, nuestra JTable usa los siguientes m!todos del modelo1
0ublic int getColumnCount() 1
return data+*,.lengt"/
6
0ublic int getRowCount() 1
return data.lengt"/
6
El primero le sirve para acotar el nmero de columnas. 2i tiene ( columnas, no pregutar, por la
onceava...
El segundo le sirve para acotar el nmero de registros disponibles.
Jinalmente, una vez tiene claro cu,ntas columnas y cu,ntos registros tiene el modelo de datos,
pregunta por el valor concreto de una celda usando el m!todo 7bject getValueAt%int
row8ndex' int colu!n8ndex(. En nuestro caso, lo podr'amos implementar f,cilmente as'1
0ublic 7bject getValueAt%int row8ndex' int colu!n8ndex( 1
return new 8nteger%data+row8ndex4),+colu!n8ndex,(/
6
7bservemos que esta es una implementaci"n sumamente ineficiente. Hay que llenar una matriz y
despu!s consultarla. Esto puede no ser caro para los ;)) primeros nmeros, pero si queremos
traba0ar, por e0emplo, con los K)).))) primeros nmeros, nuestra implementaci"n empezar'a a
renquear.
:eamos una implementaci"n m,s eficiente1
0ublic int getColu!nCount%( 1
return ./
6
0ublic int getRowCount%( 1
return 9*****/
6
0ublic 7bject getValueAt%int row8ndex' int colu!n8ndex( 1
if %colu!n8ndex -- *( 1
return new 8nteger%row8ndex(/
6
return new 8nteger%%row8ndex5.((/
6
En esta segunda implementaci"n optimizamos al m,-imo los recursos de memoria ya que no
= de ;;
almacenamos ningn valor. #os valores se calculan en tiempo de e0ecuci"n.
JTa2le ) M7%0 un 6al e;e64lo con JDB%
2i bien el e0emplo anterior es bastante ilustrativo y nos puede venir bien para implementar algunos de
nuestros modelos, no e0emplifica el caso m,s t'pico1 los datos a representar provienen de una
consulta a la base de datos.
#legados a este punto, optamos por una soluci"n t'picamente ineficiente como esta1
tate!ent st!t - null/
Resultet rs - null/
Vector rows - new Vector%(/
tring select - :;L;CT <7M=R;' A$;LL8D7)' A$;LL8D7. >R7M $;R7<A?/
try 1
st!t - connection.createtate!ent%(/
rs - st!t.execute@uery%select(/
w"ile %rs.next%(( 1
tring no!bre - rs.gettring%)(/
tring a0ellido) - rs.gettring%.(/
tring a0ellido. - rs.gettring%A(/
Vector row - new Vector%(/
row.add;le!ent%no!bre(/
row.add;le!ent%a0ellido)(/
row.add;le!ent%a0ellido.(/
rows.add;le!ent%row(/
6
6 catc" %@L;xce0tion e( 1
e.0rinttacBTrace%(/
6
finally 1
if %st!t C- null( 1
try 1
st!t.close%(/
6 catc" %@L;xce0tion e( 1
6
6
6
Vector col<a!es - new Vector%A(/
col<a!es.add;le!ent%:<o!bre?(/
col<a!es.add;le!ent%:$ri!er A0ellido?(/
col<a!es.add;le!ent%:egundo A0ellido?(/
DefaultTableModel !odel - new DefaultTableModel%rows' col<a!es(/
!iTabla.setModel%!odel(/
Como la lista de personas sea la de la gu'a telef"nica de Espa6a, no hay JTable que lo soporte.
Lste suele ser el problema al que nos enfrentamos. Cargar toda la tabla en memoria es realmente
costoso.
An+lisis -el 4ro2le6a
Ji0!monos en el primer e0emplo. El modelo, en realidad, no contiene datos. #os calcula. Es eficiente
porque no tiene un lento proceso de carga y porque pr,cticamente no usa memoria. 2implemente,
proporciona a la JTable lo que !sta le pide.
En nuestro e0emplo $%&C el modelo contiene todos los datos. Hay que cargarlos y almacenarlos en
memoria. <o es, pues, eficiente si los datos son muchos.
K de ;;
7bservemos, sin embargo, que los datos ya est,n en la base de datos. 2i esto es as', Dpor qu! no
.calculamos/ los datos que nos pide la JTable pidi!ndoselos a nuestra base de datos y simplemente
le retornamos lo que necesitaF
"n 6o-elo 4ro4orciona -a*os al -ele5a*e si5uien-o un 4ro*ocolo concre*o, no es necesario
(ue l *en5a los -a*os< Bas*a con (ue los su6inis*re 8calcul+n-olos u o2*enin-olos -e un
*ercero 2a;o -e6an-a:<
"NA .O&IBLE &OL"%I3N0 &crolla2leTa2leMo-el
Hasta la aparici"n de $%&C (.), no pod'amos hacer otra cosa que cargar los datos resultantes de
nuestra consulta en memoria. El Resultet s"lo pod'a moverse en una direcci"n1 hacia adelante.
<o pod'a, pues, dar respuesta a los requerimientos de una tabla capaz de moverse hacia adelante y
hacia atr,s. 8ero a partir de $%&C (.), disponemos de Resultets que pueden moverse
libremente por el con0unto de resultados de una consulta. El modelo, pues, puede limitarse a
.calcular/ los datos que debe devolver y e-traerlos del Resultet.
De*er6inar si nues*ro -ri=er JDB% so4or*a scrolla2le cursors
#amentablemente, no todos los drivers $%&C soportan scrollable cursors. 8ara determinar si nuestro
driver los soporta, hemos de consultar la metadata de la base de datos1
0rivate boolean su00ortscroll8nsensitive%Connection con( 1
DatabaseMetaData !d - null/
try 1
!d - con.getMetaData%(/
6 catc" %@L;xce0tion e( 1
tring errMsg - D;rror getting database !etadata.D/
t"row new crollableTableModel;xce0tion%errMsg' e(/
6
try 1
return !d.su00ortsResultetTy0e%
Resultet.TE$;FCR7LLF8<;<8T8V;(/
6 catc" %@L;xce0tion e( 1
tring errMsg - D;rror getting database !etadata.D/
t"row new crollableTableModel;xce0tion%errMsg' e(/
6
6 GG su00ortscroll8nsensitive%(
"so -e scrolla2le cursors
Como hemos visto, para que nuestro modelo funcione debemos disponer de scrollable cursors.
2uponiendo que su0ortscroll8nsensitive%( nos devuelva true, podemos definir un
tate!ent que use scrollable cursors1
st!t - connection.createtate!ent%Resultet.TE$;FCR7LLF;<8T8V;'
Resultet.C7<CHRFR;ADF7<LE(/
<o entrar! aqu' en detalles sobre la sinta-is de este m!todo, s"lo dir! que el primer par,metro
establece el tipo de scroll y el segundo, el nivel de aislamiento del cursor.
O2*enci>n ) re*orno -e los -a*os
Una vez disponemos de nuestro Resultet scrollable, hemos de utilizar sus posibilidades
? de ;;
sobrescribiendo el m!todo getValueAt%(1
0ublic 7bject getValueAt%int row8ndex' int colu!n8ndex( 1
int row<dx - row8ndex 3 )/
int col<dx - colu!n8ndex 3 )/
try 1
resultet.absolute%row<dx(/
return resultet.get7bject%col<dx(/
6 catc" %@L;xce0tion e( 1
tring errMsg - D;rror getting value at D 3
row8ndex 3 D' D 3 colu!n8ndex/
t"row new crollableTableModel;xce0tion%errMsg' e(/
6
6
#o primero que hace nuestro m!todo es traducir las coordenadas de JTable a coordenadas de
$%&C. En $%&C se empieza a contar desde ;, y en el resto del mundo $ava, se empieza a contar
desde ). As', si JTable nos pide los datos del registro ), columna ), hemos de traducirlo a $%&C
como registro ;, columna ;.
A continuaci"n situamos el cursor en el registro $%&C solicitado1
resultet.absolute%row<dx(/
Una vez situado el cursor, obtenemos los datos almacenados en la columna $%&C que se nos pide1
resultet.get7bject%col<dx(/
7bs!rvese que pedimos y devolvemos un 7bject.
Las clases -e las colu6nas
JTable es capaz de mostrar nuestros datos en funci"n de su tipo. 8ara ello utiliza clases que
implementan la interf'cie TableCellRenderer. 8ero, como es l"gico, alguien tiene que decirle
qu! clase de ob0eto recibe. 2i no se le dice, utiliza el m!todo totring%( del ob0eto de datos para
mostrar su contenido.
En nuestro caso, devolvemos un 7bject y, si no le proporcionamos m,s datos, nos mostrar, lo que
devuelva el m!todo totring%( del ob0eto que devolvemos.
2i no hay un renderer para un tipo de ob0eto concreto, tambi!n utiliza el m!todo totring%( de
dicho ob0eto.
Es conveniente, pues, indicarle qu! clase de ob0eto le estamos devolviendo para cada columna. Esto
se lleva a cabo implementando el m!todo abstracto getColu!nClass%( de
AbstractTableModel. #o cierto es que, por e0emplo, DefaultTableModel no implementa
este m!todo. Un motivo m,s para utilizarlo con precauci"n.
#a implementaci"n para nuestro modelo podr'a ser la siguiente1
List colClasses - null/
+...,
0ublic Class getColu!nClass%int colu!n8ndex( 1
if %colClasses -- null( 1
colClasses - new ArrayList%(/
ResultetMetaData !d - null/
try 1
!d - resultet.getMetaData%(/
int colCount - !d.getColu!nCount%(/
for %int i - */ i 2 colCount/ i33( 1
try 1
A de ;;
tring class<a!e - !d.getColu!nClass<a!e%i 3 )(/
Class c - Class.for<a!e%class<a!e(/
colClasses.add%c(/
6 catc" %Class<ot>ound;xce0tion e( 1
tring errMsg - D;rror getting colu!n classes.D/
t"row new crollableTableModel;xce0tion%errMsg' e(/
6
6 GG for i
6 catc" %@L;xce0tion e( 1
tring errMsg - D;rror getting colu!n classes.D/
t"row new crollableTableModel;xce0tion%errMsg' e(/
6
6
Class c - %Class(colClasses.get%colu!n8ndex(/

return c/
6
Como puede verse, la informaci"n sobre el tipo del ob0eto retornado proviene de
ResultetMetaData. 8ara cada una de las columnas, preguntamos cu,l es el nombre de la clase
*getColu!nClass<a!e%i 3 )(+, una vez m,s traduciendo coordenadas de JTable a $%&C.
A partir del nombre de la clase, obtenemos la Class1 Class c - Class.for<a!e
%class<a!e(/ que es lo que devolvemos a la $3able. Ella ya se encargar, de ver c"mo muestra
los datos de esa clase.
O2*enci>n -e los no62res -e las colu6nas
Como hemos visto, una de las cosas que JTable pide al modelo son los nombres de las columnas.
8odemos obtener estos nombres directamente del Resultet utilizando la clase
ResultetMetaData1
ArrayList col<a!es - null/
+...,
ResultetMetaData rs!d - null/
try 1
rs!d - resultet.getMetaData%(/
int colCount - rs!d.getColu!nCount%(/
if %colCount -- *( 1
GG T7D7I <o "ay colu!nasC
6
t"is.col<a!es - new ArrayList%(/
for %int i - */ i 2 colCount/ i33( 1
tring colLabel - rsmd.getColumnLabel(i+1);
t"is.col<a!es.add%colLabel(/
6
6 catc" %@L;xce0tion e( 1
e.0rinttacBTrace%(/
tring errMsg - D;rror getting ResultetMetadataD/
t"row new crollableTableModel;xce0tion%errMsg' e(/
6
7bs!rvese que utilizo el m!todo getColu!nLabel%( para obtener el nombre de la columna,
cuando pareciera m,s l"gico usar el m!todo getColu!n<a!e%(. #o cierto es que
getColu!nLabel%( devuelve lo mismo que getColu!nCount%(, e-cepto si especificamos
una etiqueta espec'fica en nuestra consulta 2E#1
;L;CT < A :<o!bre?' A A :A0ellidos? >R7M $;R7<A
@ de ;;
En este e0emplo, getColu!n<a!e%( devolver'a < y A, mientras que getColu!nLabel%(
devolver'a <o!bre y A0ellidos.
7bviamente, nuestro modelo debe ofrecer la posibilidad de especificar una ArrayList con los
nombres de las columnas.
#"gicamente, habr, que sobrescribir el m!todo getColu!n<a!e%(1
0ublic tring getColu!n<a!e%int colu!n( 1
return %tring(col<a!es.get%colu!n(/
6
%uan*as colu6nas'
Como hemos visto m,s arriba, una de las cosas que JTable necesita saber es el nmero de
columnas del modelo. 8ara ello usa el m!todo getColu!nCount%( que podemos implementar
como sigue1
0ublic int getColu!nCount%( 1
return col<a!es.si#e%(/
6
%uan*os re5is*ros'
3al como hemos comentado, JTable necesita saber tambi!n cu,ntos registros tiene el modelo para
poder acotar los par,metros pasados al m!todo getValueAt%int row8ndex' int
colu!n8ndex(. 8ara ello utiliza el m!todo getRowCount%(, que podr'a ser implementado, en
nuestro caso, de la siguiente manera1
int rowCount - 4)/
+...,
0ublic int getRowCount%( 1
if %t"is.rowCount -- 4)( 1
try 1
resultet.last%(/
t"is.rowCount - resultet.getRow%(/
6 catc" %@L;xce0tion e( 1
tring errMsg - D;rror scrolling to latest row.D/
t"row new crollableTableModel;xce0tion%errMsg' e(/
6
6
%isponemos de la variable rowCount inicializada a 4), lo que nos indicar, que todav'a no hemos
calculado su valor.
El el m!todo getRowCount%(, pasamos a calcular su valor siempre que !ste valga 4) *es decir,
siempre que todav'a no lo hayamos inicializado+. 8ara ello, situamos el cursor en el ltimo registro
*resultet.last%(+ y asignamos a rowCount el valor devuelto por el m!todo getRow%(I
esto es, el nmero del ltimo registro que, en notaci"n $%&C equivale al nmero de registros.
Ren-i6ien*os
Entramos aqu' en el apartado m,s pr,ctico de todos1 qu gano en cada caso?
Hemos comentado ya que el modelo ArrayListTableModel supon'a una me0ora de
rendimiento del (=> respecto al modelo DefaultTableModel. #as pruebas realizadas sobre la
misma base de datos con crollableTableModel me indican que la me0ora de rendimiento
B de ;;
respecto a DefaultTableModel es, apro-imadamente, del ?00@.
LA %LA&E &crolla2leTa2leMo-el
Como he comentado m,s arriba, pongo a disposici"n pblica la clase crollableTableModel.
2i bien, hasta ahora he comentado algunos aspectos de la implementaci"n, no he hablado todav'a del
uso. :amos, pues, a ello.
%ons*ruc*ores
4u2lic &crolla2leTa2leMo-el8%onnec*ion con, &*rin5 selec*:
.ar+6e*ro %o6en*ario
con Una cone-i"n abierta con la base de datos
selec* #a instrucci"n ;L;CT necesaria para obtener los datos
#os nombres de las columnas se obtienen a partir del ResultetMetaData, tal como he
comentado m,s arriba.
&crolla2leTa2leMo-el8%onnec*ion con, &*rin5 selec*, Lis* colNa6es:
.ar+6e*ro %o6en*ario
con Una cone-i"n abierta con la base de datos
selec* #a instrucci"n ;L;CT necesaria para obtener los datos
colNa6es Una java.util.List *p.e. ArrayList+ con los nombres de las columnas
El nmero de elementos de col<a!es deber, coincidir con el nmero de columnas devuelto por la
consulta.
4u2lic &crolla2leTa2leMo-el8Resul*&e* rs:
.ar+6e*ro %o6en*ario
rs Un Resultet configurado con croll 8ntensive.
Recordemos que para que el Resultet soporte scroll, debemos especificarlo en el momento de
creaci"n del tate!ent. 8or e0emplo1
st!t - connection.createtate!ent%Resultet.TE$;FCR7LLF;<8T8V;'
Resultet.C7<CHRFR;ADF7<LE(/
#os nombres de las columnas se obtienen a partir del ResultetMetaData, tal como he
comentado m,s arriba.
;) de ;;
4u2lic &crolla2leTa2leMo-el8&*a*e6en* s*6*:
.ar+6e*ro %o6en*ario
s*6* Un tate!ent configurado con croll 8ntensive conteniendo un
Resultet.
#os nombres de las columnas se obtienen a partir del ResultetMetaData, tal como he
comentado m,s arriba.
4u2lic &crolla2leTa2leMo-el8Resul*&e* rs, Lis* colNa6es:
.ar+6e*ro %o6en*ario
rs Un Resultet configurado con croll 8ntensive.
selec* #a instrucci"n ;L;CT necesaria para obtener los datos
colNa6es Una java.util.List *p.e. ArrayList+ con los nombres de las columnas
4u2lic &crolla2leTa2leMo-el8&*a*e6en* s*6*, Lis* colNa6es:
.ar+6e*ro %o6en*ario
&*6* Un tate!ent configurado con croll 8ntensive conteniendo un
Resultet.
selec* #a instrucci"n ;L;CT necesaria para obtener los datos
colNa6es Una java.util.List *p.e. ArrayList+ con los nombres de las columnas
E;e64lo -e uso
El siguiente c"digo muestra un sencillo e0emplo de uso de crollableTableModel, usando tan
solo una conne-i"n a base de datos y un select1
0ublic class crollableTableModelTest 1
0ublic static void !ain%tring+, args( 1
Connection con - null/
[... Carga del Driver JDBC y connexin a BD ...]
J>ra!e f - new J>ra!e%(/
f.setDefaultClose70eration%J>ra!e.;J8TF7<FCL7;(/

JTable tabResults - new JTable%(/
Jscroll$ane s0TabResults - new Jscroll$ane%tabResults(/
f.getContent$ane%(.add%s0TabResults' =orderLayout.C;<T;R(/
tring sel - :;L;CT 5 >R7M $;R7<AL?/
crollableTableModel !odel - new crollableTableModel%con' sel(/
tabResults.setModel%!odel(/
f.0acB%(/
GG Ventana centrada en la 0antalla
f.setLocationRelativeTo%null(/
f.setVisible%true(/
6 GG !ain%(
6
;; de ;;

También podría gustarte