IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Composants Java Discussion :

TableCellEditor a du mal a répondre


Sujet :

Composants Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Inscrit en
    Mars 2002
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 66
    Par défaut TableCellEditor a du mal a répondre
    Salut,

    J'ai fais plusieurs applications et je tombe souvent sur un problème bénin, mais a la longue agaçant.

    Si je fais un éditeur de cell qui utilise le JComboBox, ouvrir un combo box dans une cellule n'est pas un problème. Sauf que si j'ouvre le popup menu d'un combo box, et que j'essaie d'en ouvrir un deuxième directement après, (sans fermer le popup) le deuxième ne s'ouvrira pas. Même qu'on peut quelque fois le voir s'ouvrir et se refermer immédiatement. Si tu clique ailleur pour que le combo box disparraisse, il n'y a plus de soucis, le 2e combo va s'ouvrir.

    J'ai pris habitude de voir ce problème dans mes applications, mais j'avoue que j'aimerais trouver la solution...

    Voici un exemple le plus simple que j'ai pu faire pour démontrer le problème:

    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
     
    import java.awt.Component;
    import javax.swing.DefaultCellEditor;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JTable;
    import javax.swing.table.TableCellRenderer;
     
     
    public class TestTableCombo{
     
        public static void main(String[] args) throws Exception{
            JFrame fr = new JFrame();
            fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JTable tbl = new JTable(5, 5);
     
            tbl.setDefaultRenderer(Object.class, new TableCellRenderer(){
                JComboBox comp = new JComboBox();
                public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                    comp.removeAllItems();
                    comp.addItem(value);
                    return comp;
                }
            });
     
            tbl.setDefaultEditor(Object.class, new DefaultCellEditor(new JComboBox(new String[]{"1", "2", "3", "4", "5"})));
     
            fr.add(tbl);
            fr.pack();
            fr.setVisible(true);
        }
    }

  2. #2
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,



    En effet c'est assez ennuyeux

    Le problème vient surement du fait que cela utilise une seule et unique JComboBox pour tous les éditeurs. Lorsque tu cliques sur une nouvelle cellule la JComboBox est déplacé puis reçois les évènements pour son activation... mais ils doit surement y avoir dans ce cas là des évènements qui se "croisent" et qui produise ce bug : en clair après avoir été déplace la combo doit recevoir une évènement qui produit la fermeture du popup

    Une solution serait d'utiliser un éditeur qui alternerait entre deux JComboBox pour éviter ce désagrément. Ça à l'air de fonctionner :
    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
    public class ComboTableCellEditor extends AbstractCellEditor implements TableCellEditor {
    	private final JComboBox combo1;
    	private final JComboBox combo2;
    	private JComboBox current;
     
    	public ComboTableCellEditor(Object...values) {
    		this(new DefaultComboBoxModel(values));
    	}
     
    	public ComboTableCellEditor(ComboBoxModel model) {
    		this.combo1 = new JComboBox(model);
    		this.combo2 = new JComboBox(model);
    		this.current = null;
    	}
     
    	public Object getCellEditorValue() {
    		return this.current.getSelectedItem();
    	}
     
    	public Component getTableCellEditorComponent(JTable table, Object value,
    			boolean isSelected, int row, int column) {
    		// A chaque appel on alterne entre combo1 et combo2
    		this.current = (this.current==this.combo1) ? this.combo2 : this.combo1;
    		// Et on initialise la valeur :
    		this.current.setSelectedItem(value);
    		return this.current;
    	}
    }


    Sinon une petite remarque graphique : personnellement je trouve que le fait d'utiliser des JComboBox également comme renderer n'est pas très lisible

    Dans un cas similaire je m'était fait un renderer couplé à un MouseMotionListener sur la JTable, afin de changer dynamiquement la cellule au survol de celle-ci :

    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
    public class OnMouseOverRenderers implements TableCellRenderer, MouseMotionListener {
     
    	private TableCellRenderer standard;
    	private TableCellRenderer over;
     
    	private int currentRow = -1;
    	private int currentCol = -1;
     
    	/**
             * Permet d'associer à la fois le renderer et le listener.
             * (l'un sans l'autre cela ne fonctionnera pas)
             */
    	public static void setDefaultRenderers(JTable table, Class<?> columnClass, TableCellRenderer standard, TableCellRenderer over) {
    		OnMouseOverRenderers instance = new OnMouseOverRenderers(standard, over);
    		table.setDefaultRenderer(columnClass, instance);
    		table.addMouseMotionListener(instance);
    	}
     
    	private OnMouseOverRenderers(TableCellRenderer standard, TableCellRenderer over) {
    		this.standard = standard;
    		this.over = over;
    	}
     
    	public Component getTableCellRendererComponent(JTable table, Object value,
    			boolean isSelected, boolean hasFocus, int row, int column) {
    		// On renvoi vers le renderer selon les index :
    		if (row==currentRow && column==currentCol) {
    			return over.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    		}
    		return standard.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    	}
     
    	public void mouseDragged(MouseEvent e) {
    		// empty
    	}
     
    	public void mouseMoved(MouseEvent e) {
    		JTable table = (JTable) e.getComponent();
    		// On récupère les coordonnées de la cellule courante :
    		Point point = e.getPoint();
    		int row = table.rowAtPoint(point);
    		int col = table.columnAtPoint(point);
    		// Si la cellule a changé :
    		if (currentRow!=row || currentCol!=col) {
    			// On récupère les coordonnées graphiques de la précédente cellule :
    			Rectangle previous = table.getCellRect(currentRow, currentCol, true);
    			// On met à jour les index de la cellule survolée :
    			currentRow = row;
    			currentCol = col;
    			// On récupère les coordonnées graphiques de la précédente cellule :
    			Rectangle current = table.getCellRect(currentRow, currentCol, true);
    			// Et on demande de repeindre les deux cellules :
    			table.repaint(previous);
    			table.repaint(current);
    		}
    	}
    }
    En gros le listener est chargé de détecter et sauvegarder le changement de cellule, en demandant à ce qu'elle soit redessiné lorsque c'est le cas, et le renderer se charge de renvoyer la demande vers le bon renderer selon que la cellule soit survolé ou pas...

    C'est juste une suggestion mais cela pourrait intéresser

    a++

  3. #3
    Membre confirmé
    Inscrit en
    Mars 2002
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 66
    Par défaut
    Merci, j'ai pas essayé, mais en effet ca semble logique.

    Ce que je trouve étrange, c'est que le même problème arrive avec d'autres editor, comme un JButton, ou un JCheckBox (si ca se trouve, ca arrive avec TOUT). Encore plus étrange est le fait que ca fais directement partie du fonctionnement en général des Renderer, et que même la classe utilitaire fournie par sun nous offre généreusement le problème.

    Pour ta suggestion, j'y avais pensé, mais comme il y a des utilisateurs imbéciles qui ne penseront pas nécessairement qu'il s'agit d'un champ éditable avant de mettre leur souris dessus, j'ai décidé de laisser ca en combo box.

    Merci encore, je redonne des news quand ce sera testé!

  4. #4
    Membre confirmé
    Inscrit en
    Mars 2002
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 66
    Par défaut
    C'est parfait!

    Comme je disait, c'est vraiment stupide que le close popup soit appelé après le open popup directement par le système.

    Merci encore

  5. #5
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Perso je n'ai jamais eu trop de soucis avec les autres type de composant...

    Citation Envoyé par CinErarY Voir le message
    Comme je disait, c'est vraiment stupide que le close popup soit appelé après le open popup directement par le système.
    Attention ceci est juste une supposition de ma part

    a++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [MFC]dialogues qui s'initialisent mal
    Par Tsunamis dans le forum MFC
    Réponses: 4
    Dernier message: 25/03/2004, 13h57
  2. Le kernel version 2.6.3-mdk mal reconnu
    Par christophe D dans le forum Administration système
    Réponses: 5
    Dernier message: 23/03/2004, 11h03
  3. Pb de pointeur mal détruit
    Par olive_le_malin dans le forum MFC
    Réponses: 20
    Dernier message: 15/01/2004, 22h20
  4. Réponses: 3
    Dernier message: 12/05/2003, 13h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo