2009-09-04 8 views
2

Scénario:Evénement JTable + TableModel de récupération de cache pour une instanciation paresseuse?

Vous utilisez une table JTable avec un TableModel personnalisé pour afficher le contenu de certaines collections situées dans une base de données ou sur le réseau ou autre.

La force brute pour faire ce travail est de charger toute la collection à la fois. Disons que ce n'est pas pratique en raison des ressources nécessaires. Le moyen le plus simple de contourner ce problème consiste à récupérer des lignes à la demande, une ligne à la fois, lorsque la table JTable affiche chaque ligne et appelle TableModel.getValueAt(); Cache si nécessaire. Cela provoque beaucoup de hits à la base de données, cependant.

Existe-t-il un moyen d'écouter les événements scroll/viewport pour un JTable, pour déterminer les lignes qu'il va afficher avant de rendre chaque cellule? Si c'est le cas, j'aimerais intercepter et faire en sorte que mon TableModel personnalisé préextrait une page à la fois. Pour clarifier, il s'agit ici de pouvoir extraire le contenu d'un groupe de rangées de tables visibles en un seul lot, plutôt que d'avoir à chercher le contenu de chaque rang par lui-même.

+0

Afin de garder la vue-modèle comme relation 1-n, je pense qu'il est préférable de ne pas interroger la fenêtre d'affichage, mais de simplement compter sur les demandes réelles effectuées sur le modèle. ce ne sera pas plus rapide de vérifier vous-même la fenêtre. renvoyer 'null' pour les cellules non remplies ne pose aucun problème car, lorsque votre volume réel de données provient du back-end, vous pouvez simplement générer des événements tableRow. et le jtable se régénérera à nouveau. Vous pouvez réinitialiser un temporisateur à chaque requête model.getValue(). et dès que la minuterie se déclenche (disons 10 ms), récupère les enregistrements qui ont été interrogés dans une requête groupée. – Houtman

Répondre

2

En effet, c'est exactement ce que permet JTable. afaik Si la méthode getRowCount() reflète exactement le nombre d'enregistrements, alors lorsque les cellules sont peintes, seule la partie visible est interrogée. Je ne pense pas que la lecture anticipée en écoutant sur la fenêtre serait plus rapide.

vous pouvez attendre toutes les demandes getvalue. enregistrez-les, renvoyez "null" ou la valeur déjà mise en cache. puis, après une valeur getvalue n'est pas appelée par exemple 20 ms faire la demande réelle pour toutes les cellules enregistrées. et déclenche des événements rowUpdated sur le modèle afin que JTable repeigne à nouveau.

** [edit] ** Vous pouvez gérer une liste des derniers enregistrements interrogés sur le modèle. votre liste n'a pas besoin d'être plus longue que la quantité de lignes visibles sur l'écran. après getValue() n'est pas interrogé pendant quelques ms, vous pouvez effectuer cette demande en bloc asynchrone à l'arrière-plan

La seule capture ici est l'algorithme de tri/filtrage. Lorsque vous interrogez la fenêtre d'affichage et que les données en dépendent, il existe une relation 1-1 entre vos données et la vue. Quelque chose que JTable lui-même n'a pas. Mais je suppose qu'il n'y a pas moyen de contourner cela. Je voudrais permettre au débogueur IDE de creuser à travers le code soleil. puis voyez comment leur implémentation de rendu découvre les lignes à repeindre. je ne sais pas par coeur.

3

Regardez l'article http://www.javaworld.com/javaworld/javatips/jw-javatip137.html. Dans cet article il y a un TableModel personnalisé qui est capable de récupérer des "morceaux" de lignes de la base de données

Une autre solution au scénario bien que ce ne soit pas exactement ce que vous recherchez serait de charger paresseux chaque ligne au lieu de la prélecture. Voir mon propre message (recherche google pour "JTable lié à une base de données avec chargement paresseux") sur la façon de le faire. L'idée est que lorsque le tablemodel est demandé pour une ligne qui n'est pas mise en cache/chargée, elle retourne une chaîne "wait..retrieving" pour chaque colonne (en supposant que toutes les colonnes sont des chaînes). et en même temps, il planifiera une tâche dans un autre thread (en utilisant un ExecutorService). Ensuite, la tâche récupérera les données de la base de données et mettra à jour le modèle de données. Dans mon post, j'ai utilisé des bindings Beans donc au lieu d'un tablemodel personnalisé, j'ai utilisé une liste personnalisée. Mais je suis sûr que vous pouvez extrapoler l'idée.