Accès rapide :
La vidéo
Présentation du composant KDatabaseTree
Testons notre composant graphique
Cette vidéo vous apprend à coder une classe dérivant de JTree qui affiche les éléments (les tables) présents dans une base de données SQL, de manière hiérarchique. La connaissance préalable de JDBC est vivement conseillée.
Ce composant graphique permet d'afficher les éléments contenus dans une base de données relationnelles. La version proposée n'affiche que les tables, mais je vous invite à y afficher aussi les vues et les procédures stockées de la base de données. Voici un capture d'écran du composant KDatabaseTree.
JTree
malgré ce que laisse présager le nom du composant. En réalité ce composant dérive de la classe
JScrollPane
, ce qui permet l'affichage de barres de scrolling, si nécessaire. Par contre ce JScrollPane
contient bien
une instance de la classe JTree
.
Voici le code de la classe KDatabaseTree.
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 |
package fr.koor.swing.jdbc; import java.awt.Component; import java.awt.Dimension; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.sql.Connection; import java.util.EventListener; import java.util.EventObject; import java.util.Vector; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreePath; import fr.koor.swing.jdbc.KDatabaseTreeNode.UserObject; public class KDatabaseTree extends JScrollPane { private static final long serialVersionUID = 5063144763332643221L; private Vector<DatabaseSelectionListener> databaseSelectionListeners = new Vector<DatabaseSelectionListener>(); private JTree jTree = new JTree(); public KDatabaseTree() { super(); this.setPreferredSize( new Dimension( 300, 200 ) ); this.setViewportView( jTree ); jTree.addMouseListener( new MouseAdapter() { @Override public void mouseClicked(MouseEvent mouseevent) { if ( mouseevent.getClickCount() == 2 ) { // Double click fireTableSelectionChanged( jTree.getSelectionPath() ); } } }); } public void setConnection( Connection connection ) { if ( connection == null ) { jTree.setModel( null ); return; } try { KDatabaseTreeNode rootNode = new KDatabaseTreeNode( connection ); jTree.setModel( new DefaultTreeModel( rootNode ) ); jTree.setCellRenderer( new DatabaseCellRenderer() ); jTree.expandRow( 1 ); } catch ( Exception exception ) { exception.printStackTrace(); jTree.setModel( null ); } } // --- Ajout d'un renderer pour contrôler les icônes affichées --- private static class DatabaseCellRenderer implements TreeCellRenderer { private JLabel nodeLabel = new JLabel(); public Component getTreeCellRendererComponent( JTree tree, Object node, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { UserObject data = (UserObject) ((DefaultMutableTreeNode) node).getUserObject(); nodeLabel.setIcon( new ImageIcon( data.getIconUrl() ) ); nodeLabel.setText( data.getText() ); return nodeLabel; } } // --- Ajout d'un type de listener et de la classe d'événement associée --- public static class DatabaseSelectionEvent extends EventObject { private static final long serialVersionUID = 6132389637969225980L; private String tableName = null; public DatabaseSelectionEvent( Object source, String tableName ) { super( source ); if ( tableName == null ) throw new NullPointerException(); this.tableName = tableName; } public String getTableName() { return this.tableName; } } public static interface DatabaseSelectionListener extends EventListener { public void tableSelectionChanged( DatabaseSelectionEvent event ); } public void addDatabaseSelectionListener( DatabaseSelectionListener listener ) { this.databaseSelectionListeners.addElement( listener ); } public void removeDatabaseSelectionListener( DatabaseSelectionListener listener ) { this.databaseSelectionListeners.remove( listener ); } private void fireTableSelectionChanged( TreePath path ) { Object [] data = path.getPath(); DefaultMutableTreeNode node = (DefaultMutableTreeNode)data[ data.length-1 ]; if ( node instanceof KDatabaseTreeNode.TableTreeNode == false ) return; UserObject userObject = (UserObject) node.getUserObject(); DatabaseSelectionEvent event = new DatabaseSelectionEvent( this, userObject.getText() ); for(DatabaseSelectionListener listener : this.databaseSelectionListeners) { listener.tableSelectionChanged( event ); } } } |
Cette classe a besoin de diverses classes associées aux noeuds de l'arborescence : ces classes de noeuds sont contenues dans un seul fichier.
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 |
package fr.koor.swing.jdbc; import java.net.URL; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import javax.swing.tree.DefaultMutableTreeNode; public class KDatabaseTreeNode extends DefaultMutableTreeNode { private static final long serialVersionUID = -2126135007480343273L; public KDatabaseTreeNode( Connection connection ) throws SQLException { if ( connection == null ) return; String text = connection.getCatalog() + " database"; URL url = getClass().getResource( "/images/database.png" ); this.setUserObject( new UserObject( text, url ) ); this.add( new TablesTreeNode( connection ) ); // You can do the same for views and stored procedures } public static class TablesTreeNode extends DefaultMutableTreeNode { private static final long serialVersionUID = 5512631571960795765L; public TablesTreeNode( Connection connection ) throws SQLException { URL url = getClass().getResource( "/images/tables.png" ); this.setUserObject( new UserObject( "Tables", url ) ); DatabaseMetaData metaData = connection.getMetaData(); try ( ResultSet resultSet = metaData.getTables(null, null, "%", null) ) { while( resultSet.next() ) { this.add( new TableTreeNode( resultSet.getString( 3 ) ) ); } } } } public static class TableTreeNode extends DefaultMutableTreeNode { private static final long serialVersionUID = 2744534418719443466L; public TableTreeNode( String tableName ) { URL url = getClass().getResource( "/images/table.png" ); this.setUserObject( new UserObject( tableName, url ) ); } @Override public boolean isLeaf() { return true; } } public static class UserObject { private String text; private URL iconUrl; public UserObject( String text, URL iconUrl ) { this.text = text; this.iconUrl = iconUrl; } public String getText() { return text; } public URL getIconUrl() { return iconUrl; } } } |
Pour pouvoir tester ce composant, il vous faut une base de données, ainsi que le driver JDBC permettant la connexion à cette base de données. Prenez soin de mettre le JAR du driver JDBC accessible du CLASSPATH.
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 |
import java.awt.BorderLayout; import java.sql.Connection; import java.sql.DriverManager; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.UIManager; import javax.swing.plaf.nimbus.NimbusLookAndFeel; import fr.koor.swing.jdbc.KDatabaseTree; import fr.koor.swing.jdbc.KDatabaseTree.DatabaseSelectionEvent; public class Test extends JFrame { private static final long serialVersionUID = 4443303248990993973L; public Test() { super( "KDatabaseTree component test" ); this.setSize( 200, 300 ); this.setLocationRelativeTo( null ); this.setDefaultCloseOperation( DISPOSE_ON_CLOSE ); // --- On récupère le contentPane --- JPanel contentPane = (JPanel) getContentPane(); // --- On ajoute le composant d'affichage de contenu de la base --- String driver = "org.mariadb.jdbc.Driver"; String url = "jdbc:mariadb://localhost:3306/WebStore"; String login = "root"; String password = ""; try { Class.forName( driver ); try ( Connection connection = DriverManager.getConnection( url, login, password ) ) { KDatabaseTree tree = new KDatabaseTree(); tree.setConnection( connection ); tree.addDatabaseSelectionListener( this::displayTableName ); contentPane.add( tree, BorderLayout.CENTER ); } } catch (Exception exception) { exception.printStackTrace(); } } // --- Affiche le nom de la table double-cliquée --- public void displayTableName( DatabaseSelectionEvent event ) { System.out.println( event.getTableName() ); } // --- Point d'entrée du programme --- public static void main(String[] args) throws Exception { UIManager.setLookAndFeel( new NimbusLookAndFeel() ); Test frame = new Test(); frame.setVisible(true); } } |
Améliorations / Corrections
Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.
Emplacement :
Description des améliorations :