Bonjour, comment utiliser un tableViewer pour remplir une table avec une base de donnée?
Bonjour, comment utiliser un tableViewer pour remplir une table avec une base de donnée?
Je ne connais rien qui face cela de manière automatique, mais tu peux regarder du côté de JFace et particulièrement du composant JFace Data Binding : http://wiki.eclipse.org/index.php?ti...ng&redirect=no
Laurent
Bonjour à tous,
Je suis débutant en rcp/swt/jface/base de données (pres de 10 jours) et je dois developper une application en utilisant ces techno. Grace aux excellents turo de keulkeul (http://mbaron.developpez.com), j'arrive à prendre relativement la main sur ces techon.
Je désire à présent pouvoir afficher dans un tableview des données provenant d'une base de données sqlserver (et non des données provenant d'une classe peuplée "à la main"), et jne sais pas comment m'y prendre.
Avez vous des solutions à me proposer?
Je suis prenneur de tuto.
Merci d'avance
Ce sujet date un petit peu mais de ce que je me souviens il y a plusieurs etapes :
* créer un plugin permettan l'acces a ta base de donnée
* créer ton LabelProvider
* créer ton ContentProvider
* et utiliser ton plugin d'accés a la base dans le ContentProvider pour remplir ton Viewer.
Je vais essayer (si j'ai le temps) de regarder exactement comment j'avais fait (car depuis j'ai fait pas mal d'autres choses )
Merci de ta réactivité.
Je reste attentif à un autre élément de réponse (au cas ou tu retrouverais des sources) et je continue de chercher de mon coté.
Slt stachus,
Par rapport à ta reponse, jne vois pas (ou ne comprend pas) le but de créer un plugin permettant l'acces a ma base de donnée, ni celui d'utiliser mon plugin d'accés a la base dans le ContentProvider pour remplir mon Viewer . De ce que je sais, le content provider permet d'adapter les données de l'input (donnée métier) afin de pouvoir les afficher. Le viewer utilise ensuite le contentprovider au travers de la méthode setInput (viewer.setInput(myData)).
Mon problème est donc celui de pouvoir avoir "myData" provenant d'une table d'une base de données.
Thx
Bonjour à tous,
Je reviens à la charge avec mon problème qui je le rapelle est celui de pouvoir alimenter ma tableview avec des données venant d'une base de données.
Je ne sais toujours pas comment le faire. Autant avec les jTable de swing, on peut définir son propre modèle de données (donc des données venant d'une table d'une base de données par exemple) et l'assigner à la jTable lors de sa création, autant dans ce cas (utilsiation d'un tableViewer), j'arrive pas, non pardon, je ne sais pas le faire
Help me please.
Bonjour,
Il faut passer par JDBC.
En très gros, tu dois :
- charger les bons pilotes qui permette d'accéder à une bdd SQL Server
- créer la connexion en renseignant le login et mot de passe
- alimenter une liste d'objets en utilisant des Statements, Resultset ou autres à partir de la connexion précédemment créée.
- donner la liste à ton TableViewer via setInput.
Ah ben voila
Oui la solution c'est exactement ca, c'est le setInput(List<> maListe, je ne m'en souvenais plus, ca fait longtemps que je n'utilise plus RCP ....
Te voila au courant
Bonsoir messieurs (et dames? ),
je reviens à la charge avec mon problème. Faut dire que depuis la derniere fois, j'ai pas mal avancé (du moins en ce qui concerne la partie acces a la base de données ou j'étais confronté à un problème auquel j'ai trouvé une solution dans le forum y afférant).
Cela dit, j'ai essayé d'appliqué tous les généreux conseils que vous m'avez donné, notemment le fait de construire ma liste (celle que je vais passer via setInput à ma vue) à partir des données venant de ma base de données (via le resulset). Cela est fait. Cependant, je bute sur un problème auquel j'essai d'apporter une réponse.
En fait, j'ai utilisé deux tutoriels pour apprendre a la fois eclipseRCP, swt et jface. Il s'agit notemment de http://mbaron.ftp-developpez.com/eclipse/jface1.pdf" et de http://www.vogella.de/articles/Eclip...e/article.html
La méthode utilisée ici consiste à avoir une classe métier (person par exemple) avec ses attributs, ses getters et ses setters. Ce sont les objets de cette classe qui sont ensuite ajouté à une liste qui est ensuite passée à viewer pour remplissage de la table. Les autres fonctionnalités implémentées ici (selection, tri sur colonne, recherche dans le tableau, ...) utilisent également cette classe.
Et c'est donc là qu'intervient mon problème. En fait, je me sert de procédures stockées pour alimenter ma table. Les résultats de l'éxéution de me requête ne peuvent donc pas faire l'objet d'une instanciation d'une quelconque classe (ce qui serait dailleurs tres lourd, vu que j'aurais plusieurs repocédures à exécuter). Je ne sais donc pas concretement comment procéder pour récupérer mes données dans la base (suite à l'éxécution d'une procédure) et ajouter à ma table des implémentations d'édition de cellule, de tri de colonnes, ou de recherche dans la table.
J'espere ne pas vous souler avec mon problème mais je compte sur vous pour m'aider à trouver comment ca se fait.
En gros, c'est peut être trop demander, mais auriez vous un exemple (code source ou lien) d'appliation en rcp/swt/jface se connectant à une base de données, et implémentant au moins le sort sur une colonne?
Merci une fois de plus
Bonjour à tous,
A mon grand désespoir et désaroi, jai toujours pas de solution à mon pb. Je vais essayer de le reformuler en plus court et en plus précis (enfin, jvais essayer).
Je voudrais donc pourvoir afficher(et y appliquer des actions comme des tris, ...) des données venant d'une base de données dans un tableViewer. Mes données venant d'une base de données, jne dispose donc pas de classe representant ces données.
A titre d'exemple, j'ai suivi un tutoriel (dont le lien est plus haut), et disposant d'une classe person (avec ses getters et ses setters), j'utilise le labelProvider suivant :
Et le contentProvider suivant :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 public class PersonLabelProvider extends LabelProvider implements ITableLabelProvider { public String getColumnText(Object element, int columnIndex) { Person person = (Person) element; switch (columnIndex) { case 0: return person.getFirstName(); case 1: return person.getLastName(); case 2: return person.getGender(); case 3: return String.valueOf(person.isMarried()); default: throw new RuntimeException("Should not happen"); } }
Sachant que je dispose d'une classe ModelProvider dans laquelle je j'instancie mes objets person et qui contient une méthode getPersons qui est utilisée par la méthode setInput sur mon viewer.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 public class PersonContentProvider implements IStructuredContentProvider { @Override public Object[] getElements(Object inputElement) { @SuppressWarnings("unchecked") List<Person> persons = (List<Person>) inputElement; return persons.toArray(); } }
Je voudrais donc, s'il vous plait pouvoir effectuer la même chose qu'avec ma classe person, mais avec des données provenant directement d'une base de données et non d'un bean (je crois que cest comme cela qu'on les appele, non?).
So please help me
Jsuis en train de creuser une idée. Dites moi ceque vous en pensez. Au lieu d'avoir une classe metier (comme la classe "person" précédente), jvais créer une classe TableRow qui representera une ligne de mon resulset. ce serait donc cette classe que j'utiliserais dans monn label provider de la maniere suivante :
Pour l'instant je compte mettre comme attributs dans cette classe,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 public class PersonLabelProvider extends LabelProvider implements ITableLabelProvider { public String getColumnText(Object element, int columnIndex) { TableRow tblRow = (TableRow) element; ... } } }
- le num de la ligne
- une liste des élements de la ligne. Liste qui me sera renvoyée par l'éxécution de ma procédure stockée à travers mon resulset.
Voilà globalement l'idée que j'ai en tête, mais étant noviste dans le domaine, jne vois pas comment bien organiser mes sources. Que mettre exactement dans mon contentProvider, dans mon labelProvider? Ou et comment construire mon modèle de données (à passer ensuite à la vue sous forme de liste via le setInput) à partir des données provenant de la base de données. Remarquons en passant que je devrais grâce aux données de mon métadata, construire (noms et nombres de colonnes) a chaque fois la table swt.
En espérant vos réponses, bn code.
Ca va dépendre de la structure de ta base de donnée.
Pour récupérer le résultat d'une procédure stockée, il faut utiliser un CallableStatement
Est-ce que tu arrives au moins à te connecter à la bdd ?
Qu'est-ce que tu n'arrives pas à faire concrètement ?
Merci desert de ta réponse, je commencais a croire que c'est le désert ici (ok jsors bientôt ...)
Pour être plus sérieux, on met à ma disposition des procédures stockées que je dois exécuter et afficher les résultats dans des tableViewer. Je ne connais pas le contenu de ces procédures, ce que'elle doivent renvoyer comme information et le nombre de collonnes qui seront renvoyées. Je dois donc faire quelque de générique.
Pour l'instant, dans un projet java (non rcp), j'ai (dans un souci d'initiation aux datasource JDBC que je dois utiliser dans ce projet) pu me connecter à ma base de données, exécuter ma procédure (grâce entre autres aux CallableStatement), récuperer et afficher mes données et les informations sur mes données (nom des colonnes).
J'avais également, comme je l'ai expliqué plus haut, fait un tutoriel qui m'apprenais à utilser jface et les tableViewer, tutoriel qui se basais non pas sur des données venant d'une table mais sur des données venant de l'instanciation d'une classe (person en occurence).
Je voudrais donc, pouvoir afficher mes données (celle que j'arrive à recupérer dans ma base de données) dans un tableViewer.
Je sais grossomodo que je dois passer ma liste d'objets(venant de la base den données) à ma vue via la méthode setInput. Que je dois adapter mes providers (label et content) à des infos venant d'une base de données et non d'une table. Mais étant débutant, jne sais pas comment organiser et coder tout cela.
Mon maître de stage allant de me taper sur les doigts, jmen remet à vous.
Je vois...
Tu n'as qu'à dire à ton maître de stage que c'est le désert sur le forum SWT de developpez...
Non, plus sérieusement, ton idée postée plus haut n'est pas mauvaise. Maintenant, cela me paraît assez complexe à mettre en oeuvre (du moins pour moi) étant donné que le nombre de colonnes peut varier ainsi que le type d'attribut.
En imaginant que ta classe TableRow possède une liste de string où chaque ligne de cette liste correspond à une colonne, à chaque récupération de données, pour afficher chaque TableRow avec tous ses attributs, il faudrait ajouter ou retirer des colonnes à ta table en fonction de la taille de la liste de string la plus grande. Sauf si tu connais par avance le nombre max d'attributs que tu recevras d'une procédure quelconque mais ce n'est apparemment pas le cas.
Merci desert de ton intérêt pour mon pb.
J'imagine que tu as deja eu à faire des appli rcp qui interagissent avec une base de données. Si oui, lorsque tu devais visualiser les resultats de tes reqûetes, n'as tu pas été confronté à un problème comme le mien? En d'autres termes, à quoi ressemblent tes profiders (label et content), ainsi que tes classes fournissant tes modeles de données (modelProviders)?
Merci une fois de plus
Bonjour les gens.
J'ai enfin pu résoudre mon problème. Cela a été fait en creusant l'idée que j'avais esposé un peu plus haut. Voici donc les principales sources :
- ModelProvider :
- TableRow
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 /** * Singleton permetant de fournit une collection de TableRow. */ public class ModelProvider { private static ModelProvider content; // mon singleton private List<TableRow> tblRows; // liste à paser au viewer par la suite /** * Constructeur du modele. C'est là que j'ouvre ma connexion, recupère mes données * remplie ma liste et ferme la connexion */ private ModelProvider() { tblRows = new ArrayList<TableRow>(); TableRow tblRow ; int rowNumber; Object[] dataRow = null; /* Récupération des données dans la base de données*/ try { //initialisation du contexte System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); System.setProperty(Context.PROVIDER_URL, "file://" + FileLocator.resolve(Platform.getBundle("simpleExplorer").getEntry("/")).getPath()); //récupération de la DataSource à partir du contexte Context ctx = new InitialContext(); DataSource source = (DataSource) ctx.lookup("INTERFACES"); Connection connection = source.getConnection(); Statement st = connection.createStatement(); CallableStatement cs = connection.prepareCall("{call rep_getAnnouncePendingAcknowledgement}"); ResultSet rs = null; ResultSetMetaData metaData = null; int colCount = 0; try{ rs = cs.executeQuery(); metaData = rs.getMetaData(); colCount = metaData.getColumnCount(); System.out.println("ColCount = " + colCount); rowNumber = 0; while (rs.next()){ dataRow = new Object[colCount]; //dataRow.add(rowNumber, rs.getObject(rowNumber + 1)); for(int i=0; i<colCount; i++){ dataRow[i] = rs.getObject(i + 1); } System.out.println("Titre = " + metaData.getColumnName(rowNumber + 1)); System.out.println("Valeur de la colonne = " + dataRow[rowNumber].toString()); rowNumber++; tblRow = new TableRow(rowNumber, dataRow); tblRows.add(tblRow); } }catch (SQLException e) { System.out.println("Erreur d'éxécution de la requête"); } // on ferme toules les connexions ouvertes rs.close(); st.close(); connection.close(); } catch (Exception e) { System.err.println(e); } /* Fin de la récupération des données*/ } public static synchronized ModelProvider getInstance() { if (content != null) { return content; } else { content = new ModelProvider(); return content; } } public List<TableRow> getTblRows() { return tblRows; } }
- Les providers (label et content)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 public class TableRow { private int numRow; private Object[] elements; public TableRow (){} public TableRow (int numRow, Object[] dataRow){ this.numRow = numRow; this.elements = dataRow; } public int getNumRow() { return numRow; } public void setNumRow(int numRow) { this.numRow = numRow; } public Object[] getElements() { return elements; } public void setElements(Object[] elements) { this.elements = elements; } public Object getElementAt(int row){ return elements[row]; } }
- Ma vue
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 public class TblRowContentProvider implements IStructuredContentProvider { @Override public Object[] getElements(Object inputElement) { @SuppressWarnings("unchecked") List<TableRow> elements = (List<TableRow>) inputElement; return elements.toArray(); } @Override public void dispose() { } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } } public class TblRowLabelProvider extends LabelProvider implements ITableLabelProvider { @Override public Image getColumnImage(Object element, int columnIndex) { return null; } @Override public String getColumnText(Object element, int columnIndex) { TableRow tblRow = (TableRow) element; return tblRow.getElementAt(columnIndex).toString(); } }
Comme vous pouvez le remarquer, j'accede deux fois à la base de données. La première fois pour contruire ma table (notemment les noms des colonnes), et la seconde fois, pour la peupler.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 public class View extends ViewPart { public static final String ID = "simpleExplorer.view"; private TableViewer viewer; /** * Méthode permettant de définir le contenu de la vue */ public void createPartControl(Composite parent) { GridLayout layout = new GridLayout(2, false); parent.setLayout(layout); viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER); createColumns(viewer); viewer.setContentProvider(new TblRowContentProvider()); viewer.setLabelProvider(new TblRowLabelProvider()); viewer.setInput(ModelProvider.getInstance().getTblRows()); // Layout the viewer GridData gridData = new GridData(); gridData.verticalAlignment = GridData.FILL; gridData.horizontalSpan = 2; gridData.grabExcessHorizontalSpace = true; gridData.grabExcessVerticalSpace = true; gridData.horizontalAlignment = GridData.FILL; viewer.getControl().setLayoutData(gridData); } /** * les colonnes sont crées avec des noms vennant de la base de données * @param viewer */ private void createColumns(final TableViewer viewer) { Table table = viewer.getTable(); String[] titles = null; int[] bounds = { 100, 100, 100, 100, 100, 100, 100, 100, 100 }; /*Récupération des info métadata sur la table. Penser à le faire plus dynamiquement*/ try { //initialisation du contexte System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); System.setProperty(Context.PROVIDER_URL, "file://" + FileLocator.resolve(Platform.getBundle("simpleExplorer").getEntry("/")).getPath()); //récupération de la DataSource à partir du contexte Context ctx = new InitialContext(); DataSource source = (DataSource) ctx.lookup("INTERFACES"); Connection connection = source.getConnection(); Statement st = connection.createStatement(); CallableStatement cs = connection.prepareCall("{call rep_getAnnouncePendingAcknowledgement}"); ResultSet rs = null; ResultSetMetaData metaData = null; int colCount = 0; try{ rs = cs.executeQuery(); }catch (SQLException e) { System.out.println("Erreur d'éxécution de la requête"); } try{ metaData = rs.getMetaData(); colCount = metaData.getColumnCount(); System.out.println("colCount = "+ colCount); } catch (SQLException ex){ System.out.println(ex.getMessage().toString()); } int j = 0; titles = new String[colCount]; try{ //Remplissage de titles for (j = 0 ; j < colCount ; j++){ titles[j] = metaData.getColumnName(j+1); } }catch (SQLException ex){ System.out.println(ex.getMessage().toString()); } // on ferme toutes les connexions ouvertes rs.close(); st.close(); connection.close(); // */ } catch (Exception e) { System.err.println(e); } /*Fin récupération des infos métada*/ for (int i = 0; i < titles.length; i++) { //final int index = i; final TableViewerColumn viewerColumn = new TableViewerColumn( viewer, SWT.NONE); final TableColumn column = viewerColumn.getColumn(); column.setText(titles[i]); column.setWidth(bounds[i]); column.setResizable(true); column.setMoveable(true); } table.setHeaderVisible(true); table.setLinesVisible(true); } /** * Passing the focus request to the viewer's control. */ public void setFocus() { viewer.getControl().setFocus(); } }
Mon soucis au jour d'aujourdui, est celui de l'organisation de mes sources. J'envisage créer une classe de connexion à ma base de données (en utilisant biensur les datasource), ainsi que des methodes me permettant à terme d'initialiser une table (nom des colonnes, et premier peuplement) et de la mettre à jour (en envisageant ici que les données sont succeptibles de changer assez régulierement; changement qui devrais biensur être pris en compte au niveau de l'affichage).
Je met donc le sujet en résolu, mais je suis ouvert à d'éventuelles propositions ou orientations pouvant me guider.
Merci une fois de plus
Bravo !
C'est plus ou moins à cela que je pensais sauf pour le tableau d'objets elements de la classe TableRow que j'avais plutôt imaginé comme une liste de String mais ton choix est tout aussi bien.
Personnellement, pour dialoguer avec une bdd mono-utilisateur par exemple, j'ai une classe qui se charge de la connection (création, destruction ou récupération) et d'autres classes pour les requêtes.
Bref, bonne continuation.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager