FAQ Java GUIConsultez toutes les FAQ
Nombre d'auteurs : 37, nombre de questions : 155, dernière mise à jour : 10 octobre 2015 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de http://www.developpez.com et de l'expérience personnelle des auteurs.
Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes. Les auteurs font leur maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez nous aider en devenant rédacteur, lisez ceci.
- Quelles sont les différences entre Awt et Swing ?
- Peut-on mélanger Awt et Swing ?
- Comment faire un minuteur (timer) facilement ?
- Mon menu contextuel s'affiche hors de l'écran, que faire ?
- Comment mettre une image dans un bouton (AWT) ?
- Comment mettre une image dans un bouton (Swing) ?
- Comment rendre un JButton transparent ?
- Comment imprimer l'ensemble d'un Container (JDK 1.1.x) ?
- Comment enregistrer un Component en tant qu'image ?
- Lors d'un traitement long, l'affichage se fige, que faire ?
- Qu'est ce que l'Event Dispatch Thread (EDT) ?
- Comment vérifier que l'on est bien dans l'EDT ?
- Comment exécuter un traitement plus tard dans l'EDT ?
- Comment lancer un traitement long ?
- Comment lancer un traitement dans l'EDT depuis un autre Thread ?
- Pourquoi ma barre de progression se remplit d'un coup ?
- Comment changer le Look & Feel de mon application ?
- Comment lister les Look & Feel disponibles ?
- Comment modifier un élément du Look and Feel ?
- Comment enlever le style gras du Look and Feel par défaut ?
- Comment définir les touches par défaut ENTER et ESCAPE ?
- Comment ajouter un KeyListener à un objet JComboBox éditable ?
- Comment changer la langue d'un JComponent sans changer la langue de tout le programme ?
- Comment changer l'arrière-plan de certaines lignes d'une JList ?
- Comment changer la langue de mon application et toutes les conversions qui vont avec ?
- Comment disposer les composants en couches ou en niveaux ?
- Comment placer le même composant en plusieurs endroits simultanément ?
Tout d'abord, il faut rappeler que la librairie AWT a été développée pour la première sortie de Java version 1.0 du JDK alors que Swing n'est apparue qu'à la version 1.2 du JDK (soit Java 2). Il en résulte donc des différences fondamentales de conception entre les deux librairies.
Composant AWT : un composant AWT, lors de sa création, est associé à une fenêtre distincte (un homologue, peer en anglais) gérée par le système d'exploitation sous-jacent. Et c'est cet homologue qui est responsable de son apparence. Cette "manière" de faire, bien qu'elle ait fait ses preuves et qu'elle ait permis au langage Java de s'imposer, est très lourde (perte de performances et consommation excessive de mémoire). C'est pour cette raison que l'on qualifie les composants AWT par heavyweight (littéralement, poids lourds).
Composant Swing : par opposition, les composants Swing sont simplement dessinés à l'intérieur de leur conteneur comme s'il s'agissait d'une image, et aucun homologue du système sous-jacent ne leur est affecté. C'est pourquoi ils sont qualifiés de lightweight (composants allégés).
Nous noterons également que lors du développement avec AWT, il suffit d'ajouter les composants directement au Top-Level Container (Conteneur de Haut Niveau) tel que Frame, Applet, ..., alors que sous Swing il est nécessaire de les ajouter à un volet de contenu (cf : javax.swing.JRootPane). De manière plus explicite, je veux parler du :
Code java : | Sélectionner tout |
jframe.getContentPane().add(monComposant);
NON ! Il est impossible d'obtenir un rendu graphique correct dans une application qui mélange AWT et SWING. Des problèmes de superposition empêchent toute collaboration.
Explication : avant toute chose, il faut bien comprendre les différences entre Awt et Swing : Quelles sont les différences entre Awt et Swing ? .
Le composant JFrame comprend un objet fils qui prend en charge tout ce qui concerne le graphique, il s'agit d'une instance de JRootPane. Le composant JRootPane est lui-même structuré. Il contient un volet structuré en couches (instance de JLayeredPane) et un volet structuré en pellicules (GlassPane).
- Le composant LayeredPane permet d'insérer une barre de menus ainsi que tout autre composant (cela fait référence au fameux contentPane de jframe.getContentPane ()). il est également chargé du Z-ordering (algorithme permettant de ne dessiner que les parties non cachées, suite aux superpositions de composants).
- Le composant GlassPane représente une pellicule qui recouvre tout et qui, par exemple, peut intercepter tous les événements souris de l'interface graphique.
Démonstration :
Code java : | Sélectionner tout |
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 | import javax.swing.*; import java.awt.*; public class AWTSwing { private JComboBox combo; // Composant Swing private Button bouton; // Composant AWT public AWTSwing () { JFrame frame = new JFrame ("Peut-on melanger Awt & Swing ?"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setBounds (300, 300, 200, 300); String [] a = {"oui", "non", "peut etre"}; combo = new JComboBox (a); frame.getContentPane ().add (combo, BorderLayout.NORTH); bouton = new Button ("Coucou"); frame.getContentPane ().add (bouton, BorderLayout.CENTER); frame.setVisible (true); } public static void main (String argv []) { new AWTSwing (); } } |
- Le rendu graphique du composant "bouton" issu de la librairie AWT est délégué à son homologue (peer), par conséquent la position Z est la même que celle de la Frame (soit de haut niveau).
- Alors que le composant "combo" de type JComcoBox (Swing) n'est que "dessiné" comme une image sur le conteneur (soit de bas niveau).
La seule solution envisageable est d'uniformiser le code sur la librairie graphique utilisée, soit tout AWT, soit tout Swing !
On peut utiliser la classe java.lang.Thread ou implémenter l'interface java.lang.Runnable, mais suivant les cas de figure cela représente beaucoup de code et de contraintes. En effet, les instructions qui affectent ou dépendent d'un composant graphique Swing doivent être effectuées par le processus d'évènement (the event-dispatching thread). Par conséquent, si l'on utilise la classe Thread ou l'interface Runnable, il est nécessaire d'utiliser les méthodes : invokeLater(java.lang.Runnable) ou invokeAndWait(java.lang.Runnable) javax.swing.SwingUtilities.
La classe Timer : la classe javax.swing.Timer remplace avantageusement l'utilisation directe de thread. Elle génère un événement à intervalles réguliers (à la milliseconde). C'est le "event-dispatching thread" qui exécute l'événement, donc on peut directement modifier des objets graphiques.
Méthodes importantes : le constructeur de javax.swing.Timer :
Code java : | Sélectionner tout |
1 2 3 4 | public Timer (int delay, ActionListener listener); /** delay = l'intervalle de temps entre chaque événement. * listener = l'objet écouteur de ces événements. */ |
Code java : | Sélectionner tout |
public void start();
Code java : | Sélectionner tout |
public void stop();
JDK 1.3 et inférieur : lorsque l'on utilise la méthode show(java.awt.Component, int, int) pour afficher un javax.swing.JPopupMenu, les coordonnées correspondent au coin haut-gauche du menu. Si ces coordonnées sont trop près du bord de l'écran, une partie du menu est alors cachée. Nous allons donc surcharger la méthode show() pour que les coordonnées soient corrigées si le message est trop proche du bord de l'écran.
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | class MonPopupMenu extends JPopupMenu { public void show(Component invoker, int x, int y) { /**Dimension de l'écran */ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); /** Dimension du Menu popup */ Dimension popupSize = this.getPreferredSize(); /** Position en x,y du popup à l'écran (pour le .show) */ double xPopupEcran = invoker.getLocationOnScreen().getX() + x; double yPopupEcran = invoker.getLocationOnScreen().getY() + y; /** Si le popup déborde de l'écran sur la droite on décale sur x */ if ((xPopupEcran + popupSize.getWidth()) > screenSize.getWidth()) { x = x - (int)popupSize.getWidth(); } /** Si le popup déborde de l'écran sur le bas on décale sur y */ if ((yPopupEcran + popupSize.getHeight()) > screenSize.getHeight()) { y = y - (int)popupSize.getHeight(); } /** On affiche le popup à l'endroit judicieusement calculé :) */ super.show(invoker, x, y); } } |
Ce n'est pas directement possible en AWT, il faut créer sa propre classe MyButton permettant de le faire en dérivant, par exemple, Component pour faire un lightweigth component.
Il y a un constructeur de JButton et une méthode qui permettent d'avoir le résultat voulu en donnant l'image en argument sous forme de Icon
Code sql : | Sélectionner tout |
JButton bouton = new JButton(new ImageIcon("images/bouton.gif"));
Code sql : | Sélectionner tout |
bouton.setIcon(new ImageIcon("images/bouton.gif"));
La classe AbstractButton définit un ensemble de méthodes permettant d'indiquer comment doit se dessiner le bouton. Ainsi, on peut indiquer, par exemple, si on désire dessiner les rebords ou le contenu. Voici un exemple.
Le code ci-dessous dessine un bouton transparent, seul le texte sera affiché en rouge.
Code java : | Sélectionner tout |
1 2 3 4 5 | JButton printButton = new JButton("Imprimer"); printButton.setForeground(Color.red); printButton.setFocusPainted(false); printButton.setBorderPainted(false); printButton.setContentAreaFilled(false); |
Voilà un début de code permettant d'imprimer un Container 'cont'.
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** Récupère le travail et affiche la boite de dialogue d'impression */ PrintJob job = getToolkit().getPrintJob(frame_parent_pour_le_dialogue,"essai", null); if (job != null) { /** Récupère le Graphics dans lequel on va écrire */ Graphics g = job.getGraphics(); if (g != null) { /** Sur le Container imprime l'ensemble de ses Components */ cont.printAll(g); g.dispose(); } /** Finit le travail */ job.end(); } |
Pour enregistrer un object de type Component en tant qu'image, il faut commencer par dessiner ce composant dans une BufferedImage puis on va écrire cette image dans un fichier.
Voici un exemple qui permet d'enregistrer un composant sous forme d'image JPeg :
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public void saveImage(Component component, File destination){ BufferedImage image = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g2d = image.createGraphics(); if(!component.isOpaque()){ Color bg = component.getBackground(); bg = (bg.getAlpha() < 255) ? new Color(bg.getRed(), bg.getGreen(), bg.getBlue()) : bg; Color color = g2d.getColor(); g2d.setColor(bg); g2d.fillRect(0, 0, component.getWidth(), component.getHeight()); g2d.setColor(color); } component.paint(g2d); g2d.dispose(); try { ImageIO.write(image, "jpeg", destination); } catch (IOException e) { e.printStackTrace(); } } |
Symptômes :
La fenêtre est vide, ou il est impossible de cliquer sur le moindre composant, ou les autres fenêtres du système d'exploitation laissent des traînées grises qui ne se redessinent par sur vos fenêtres, ou encore j'ai l'impression que mon application met du temps à réagir.
Cause :
Ce problème est très classique lors d'un long traitement dans une application graphique. En Java, un Thread est chargé de toutes les opérations liées à l'affichage et à la gestion des événements, le Thread "Event Dispatching Thread" (en abrégé EDT). Si une application utilise ce Thread pour faire un traitement de plusieurs minutes, c'est autant de temps où l'application ne sera plus réactive aux actions de l'utilisateur, ni aux mises à jour graphiques (d'une barre de progression par exemple). Typiquement, vous avez du code lié au clic sur un bouton ou un menu (un ActionListener par exemple) et vous y effectuez de gros calculs ou des Thread.sleep(). Vous ne pouvez pas faire ça, les traitements de l'EDT doivent être le plus bref possible !
Solution :
La solution est assez simple à comprendre : tout traitement long doit être effectué par un autre Thread. En Java 5 et supérieur, la classe SwingWorker est très utile pour vous aider à faire ça.
L'Event Dispatch Thread, également appelée EDT, est le Thread dans lequelle l'AWT et Swing font à la fois leur affichage et leur propagation d'événements. Les composants AWT et Swing doivent uniquement être utilisés dans l'EDT. Si un composant est instancié, appelé et manipulé depuis un autre Thread, il peut potentiellement provoquer une erreur dans le programme ou ne pas s'afficher correctement.
L'EDT alterne les cycles d'affichage et les cycles de propagation d'événements. Ainsi, quand on gère un événement clavier, souris ou de sélection dans un composant, on est assuré que :
- On est bien dans l'EDT.
- Le composant n'est pas en train de se redessiner. Il sera redessiné dans un cycle d'affichage ultérieur (pas forcément le cycle suivant) si on appelle sa méthode repaint() après le traitement de l'événement. Il existe cependant des manières d'avoir un rendu immédiat lorsque l'état d'un composant est modifié, mais généralement vous ne devriez pas avoir besoin de les utiliser.
Les deux manières de vérifier que le traitement actuel se déroule bien dans l'EDT sont :
- pour l'AWT, d'invoquer la méthode statique isDispatchThread() de la classe java.awt.EventQueue.
- Pour Swing, d'invoquer la méthode statique isEventDispatchThread() de la classe javax.swing.SwingUtilities.
Tout d'abord, il est bien important de comprendre que tout traitement d'événement, tels que des écouteurs pour le clavier, la souris ou de sélections dans des composants, et implémenté de manière standard se déroule déjà dans l'EDT.
Cependant, il peut parfois être nécessaire d'effectuer un traitement "plus tard" de manière à essayer d'attendre un moment où le niveau de charge de l'EDT est moins élevé ou pour laisser le temps à l'interface graphique de faire un affichage préliminaire par exemple. Pour ce faire, il faut appeler la méthode statique invokeLater() de la classe javax.swing.SwingUtilities. Cette méthode rend immédiatement la main après avoir été invoquée.
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | // Cette méthode retourne immédiatement. SwingUtilities.invokeLater(new Runnable() { /** * {@inheritDoc} */ @Override public void run() { myButton.setText("Salut le monde !") ; } }) ; |
Les traitements longs doivent être lancés hors de l'EDT, pour cela il est possible d'utiliser un autre Thread que l'on lance manuellement ou encore d'utiliser un java.util.Timer.
Attention cependant à penser à vérifier et au besoin à changer la priorité du nouveau Thread, car cette dernière hérite automatiquement sa priorité de celle de son Thread parent dans laquelle elle a été créée (le nouveau Thread a donc la même priorité que l'EDT).
Pour Java 6 ou plus, il est recommandé d'utiliser la classe javax.swing.SwingWorker qui offre un framework permettant d'exécuter une tâche hors de l'EDT, tout en récupérant ses résultats intermédiaires et finaux dans l'EDT. Une implémentation existe pour Java 5 qui est disponible chez SwingLabs.
Il existe deux façons de faire :
- Utiliser la méthode statique invokeLater() de la classe javax.swing.SwingUtilities. Cette méthode prend en paramètre une instance de la classe Runnable qui sera exécutée ultérieurement. Cette méthode retourne immédiatement après avoir été invoquée.
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | // Cette méthode retourne immédiatement. SwingUtilities.invokeLater( new Runnable() { /** * {@inheritDoc} */ @Override public void run() { myButton.setText("Salut le monde !") ; } }) ; |
- Utiliser la méthode statique invokeAndWait() de la classe javax.swing.SwingUtilities. Cette méthode prend en paramètre une instance de la classe Runnable qui sera exécutée. Cette méthode bloque tant que l'action n'a pas été effectuée, ce qui permet, par exemple, de mettre à jour l'interface graphique quand on effectue un traitement depuis un autre Thread et de bloquer jusqu'à ce que la GUI ait été modifiée. Cette méthode ne DOIT PAS être appelée de l'EDT même.
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | // Cette méthode bloque tant que le traitement EDT n'est pas effectué. SwingUtilities.invokeAndWait( new Runnable() { /** * {@inheritDoc} */ @Override public void run() { myButton.setText("Salut le monde !") ; } }); |
Pour mieux comprendre le problème : Lors d'un traitement long, l'affichage se fige, que faire ?
Voici deux codes sources Java commentés.
JProgress : la mauvaise méthode (la vôtre ?)
JProgress2 = une solution
Pour faire cela, il faut utiliser la classe UIManager. Par exemple :
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 | try { UIManager.setLookAndFeel("mon.look.and.Feel"); //on passe au UIManager le nom complet de la classe du Look and Feel //naturellement, celle-ci doit être disponible dans le CLASSPATH } catch (InstantiationException e) { } catch (ClassNotFoundException e) { } catch (UnsupportedLookAndFeelException e) { } catch (IllegalAccessException e) {} |
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | JFrame frame = new JFrame(); frame.setVisible(true); // etc. try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); SwingUtilities.updateComponentTreeUI(frame); //force chaque composant de la fenêtre à appeler sa méthode updateUI } catch (InstantiationException e) { } catch (ClassNotFoundException e) { } catch (UnsupportedLookAndFeelException e) { } catch (IllegalAccessException e) {} |
Les Look and Feel enregistrés sont disponibles avec la méthode getInstalledLookAndFeels de la classe UIManager. Voici un exemple récupérant l'ensemble des Look and Feel sous forme de Map, dont les clefs sont les noms des L&F et les valeurs les noms des classes correspondantes.
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | public Map getLookAndFeelsMap(){ UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels(); Map map = new TreeMap(); for(int i=0; i<info.length;i++){ String nomLF = info[i].getName(); String nomClasse = info[i].getClassName(); map.put(nomLF,nomClasse); } return map; } |
Avant tout affichage, il faut appeler la méthode put(Object, Object) de la classe UIManager. Le premier paramètre correspond à l'objet à modifier, et le second est la valeur à lui donner.
Par exemple, pour mettre en blanc le fond de tous les JPanels :
Code java : | Sélectionner tout |
UIManager.put("Panel.background", new ColorUIResource(Color.WHITE));
Metal, le Look and Feel par défaut, utilise du texte en gras dans la plupart des composants Swing. Le résultat n'est pas forcément des plus esthétiques.
Heureusement, il est possible de remédier à cela en modifiant la propriété swing.boldMetal, soit directement via la classe UIManager :
Code java : | Sélectionner tout |
1 2 | // Ne pas utiliser de texte en gras (LnF Metal) : UIManager.put("swing.boldMetal", Boolean.FALSE); |
Soit en passant par les variables systèmes si l'on n'a pas accès au code source :
Code : | Sélectionner tout |
java -Dswing.boldMetal=false ... (les autres paramètres standards)
Vous souhaitez associer des boutons de votre interface graphique aux touches ENTER et ESCAPE, et ceci quel que soit le composant qui ait le focus lors de l'appui sur ces touches ?
Pour la touche ENTER, c'est très simple parce que c'est fait pour :
Code java : | Sélectionner tout |
1 2 3 4 | // - pour une JFrame maFrame.getRootPane().setDefaultButton(monBouton) // - pour une JDialog monDialog.getRootPane().setDefaultButton(monBouton) |
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | private void configureRootPane(JRootPane rootPane) { InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escPressed"); rootPane.getActionMap().put( "escPressed", new AbstractAction("escPressed") { public void actionPerformed(ActionEvent actionEvent) { onKeyEscape(); } }); } ... // - pour une JFrame configureRootPane(maFrame.getRootPane()); // - pour une JDialog configureRootPane(monDialog.getRootPane()); |
Il faut en fait ajouter le KeyListener au composant permettant l'édition de la combobox, en l'occurrence un JTextField :
Code java : | Sélectionner tout |
1 2 3 | Component c = comboBox.getEditor().getEditorComponent() ; JTextField textField = (JTextField) c ; textField.addKeyListener( new KeyListener() ) ; |
Il suffit d'utiliser la méthode setDefaultLocale de la classe JComponent.
Exemple, si j'ai un programme en français mais que je veux avoir tous mes JFileChooser en anglais :
Code java : | Sélectionner tout |
1 2 | JFileChooser.setDefaultLocale(new Locale("en","US")); // ou JFileChooser.setDefaultLocale(Locale.US) |
Pour changer l'arrière-plan de certaines lignes d'une Jlist, il faut utiliser un ListCellRenderer personnalisé :
Code java : | Sélectionner tout |
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 | class MyCellRenderer extends JLabel implements ListCellRenderer { public Component getListCellRendererComponent( JList list, Object value, // value to display int index, // cell index boolean isSelected, // is the cell selected boolean cellHasFocus) // the list and the cell have the focus { setText(value.toString()); if (isSelected) { setBackground(list.getSelectionBackground()); setForeground(list.getSelectionForeground()); } else { setBackground(list.getBackground()); setForeground(list.getForeground()); } // Ici, il faut tester si on veut changer la couleur et changer par la // couleur de notre choix if (taCondition == true){ setBackground(couleur); } setEnabled(list.isEnabled()); setFont(list.getFont()); setOpaque(true); return this; } } |
Après, il suffit d'appliquer ce renderer à la JList :
Code java : | Sélectionner tout |
1 2 | JList list = new JList(); list.setCellRenderer(new MyCellRenderer()); |
et le tour est joué.
Il suffit de changer le Locale de la JVM au démarrage.
Code java : | Sélectionner tout |
Locale.setDefault(Locale.US);// par exemple si on est en français et que l'on veut l'anglais (USA)
Code java : | Sélectionner tout |
Locale.setDefault(new Locale("en", "US"));// par exemple si on est en français et que l'on veut de l'anglais (USA)
Code : | Sélectionner tout |
Locale loc = new Locale(String langue, String pays)
Il y a deux manières de faire pour disposer ses composants en couches ou en niveaux :
- En utilisant un JLayeredPane. Cette solution est utilisable avec Swing.
- En utilisant le principe du ZOrder. Cette solution est valable pour AWT et Swing, pour toutes les classes descendant de Container.
Nous allons prendre comme exemple la disposition de deux JLabels l'un au dessus de l'autre.
Premièrement, avec un JLayeredPane :
Code java : | Sélectionner tout |
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 | import javax.swing.JLabel; import javax.swing.JLayeredPane; public class CouchesAvecJLayer extends javax.swing.JFrame { public CouchesAvecJLayer() { initComponents(); } private void placeLesCouches(){ JLayeredPane layered; JLabel dessous; JLabel dessus; layered = new JLayeredPane(); // Comme il n'y a pas vraiment de layout avec un JLayeredPane // il faut gérer soi-même les tailles et positions. layered.setPreferredSize(new java.awt.Dimension(400, 200)); // (pour simplifier on ne gère pas les positions, tout ira les // uns sur les autres). dessous = new JLabel("en dessous ! (et en partie masqué)"); dessous.setSize(dessous.getPreferredSize()); layered.add(dessous, new Integer(0)); dessus = new JLabel("au dessus !"); // Inutile, pour jouer avec l'opacité de façon à mieux faire // apparaître ce qui est dessus/dessous dessus.setOpaque(true); layered.add(dessus, new Integer(1)); add(layered); pack(); } @SuppressWarnings("unchecked") private void initComponents() { setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); pack(); } public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { CouchesAvecJLayer couches; couches = new CouchesAvecJLayer(); couches.placeLesCouches(); couches.setVisible(true); } }); } } |
Code java : | Sélectionner tout |
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 | import javax.swing.JLabel; import javax.swing.JPanel; public class CouchesAvecZOrder extends javax.swing.JFrame { public CouchesAvecZOrder() { initComponents(); } private void placeLesCouches(){ JPanel zpanel; JLabel dessous; JLabel dessus; zpanel = new JPanel(); // Le réglage du layout est particulier avec le ZOrder. // Pour simplifier on le supprime. zpanel.setLayout(null); zpanel.setPreferredSize(new java.awt.Dimension(400, 200)); dessus = new JLabel("au dessus !"); // Comme il n'y a plus de layout on doit gérer les tailles. dessus.setSize(dessus.getPreferredSize()); // Inutile, pour jouer avec l'opacité de façon à mieux faire // apparaître ce qui est dessus/dessous dessus.setOpaque(true); zpanel.setComponentZOrder(dessus, 0); dessous = new JLabel("en dessous ! (et en partie masqué)"); dessous.setSize(dessous.getPreferredSize()); zpanel.setComponentZOrder(dessous, 1); add(zpanel); pack(); } @SuppressWarnings("unchecked") private void initComponents() { setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); pack(); } public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { CouchesAvecZOrder couches; couches = new CouchesAvecZOrder(); couches.placeLesCouches(); couches.setVisible(true); } }); } } |
Ce n'est pas possible.
Pour obtenir un résultat similaire, il faut utiliser la notion de modèle, souvent attachée à un composant swing (JTable, JTree...). Le modèle Action est le plus simple, et permet de stipuler une même fonction à plusieurs boutons, ou autre composant. Il s'utilise simplement par l'AbstractAction.
Pour créer une AbstractAction :
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | class QuelleBelleAction extends javax.swing.AbstractAction { QuelleBelleAction() { putValue(NAME, "Merci, developpez.net"); } @Override public void actionPerformed(ActionEvent e) { System.out.println("BINGO ! "); } } |
Code java : | Sélectionner tout |
1 2 3 4 5 | QuelleBelleAction belle = new QuelleBelleAction(); JButton but1 = new JButton(belle); JButton but2 = new JButton(belle); paneau.add(but1); panneau.add(but2); |
Code java : | Sélectionner tout |
belle.setEnabled(false);
On peut de la même façon mettre plusieurs JTable (ou JTree, ou...) apparemment identiques, parce qu'ils ont le même modèle, et non parce que le composant graphique est le même.
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.