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

AWT/Swing Java Discussion :

Entourer une cellule en rouge après l'exécution d'une action


Sujet :

AWT/Swing Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 200
    Par défaut Entourer une cellule en rouge après l'exécution d'une action
    Bonjour,

    j'aimerais simplement entourer la bordure d'une cellule d'une JTable en rouge après l'action d'un bouton.

    Pour la création de la Jtable, j'ai le bout de code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
       this.table_phases = new JTable();
       this.table_phases.setDefaultRenderer(Object.class, new CheckDataCellRenderer());
            this.table_phases.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            this.table_phases.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
                public void valueChanged(ListSelectionEvent e) {
                    if (e.getValueIsAdjusting()) {
                         // d'autres action...
                    }
                }
            }
       }
    Et pour la gestion de l'affichage des cellules de la Jtable, j'ai le bout de code 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
    19
    20
    public class CheckDataCellRenderer extends DefaultTableCellRenderer {
     
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     
                Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
     
                if (cell instanceof JLabel) {
                    JLabel label = (JLabel) cell;
     
                    if (label.getText().isEmpty()) {
                        label.setBorder(BorderFactory.createLineBorder(Color.red));
                    } else {
                        label.setBorder(Constants.DEFAULT_BORDER);
                    }
                }
     
                return cell;
            }
        }
    Pour le moment, lorsqu'une cellule est vide elle est entourée en rouge.
    J'aimerais juste appliquer cette action lors d'un click sur un bouton par exemple.

    J'avais pensé à initialiser lors de mon click une map pour les cellules à contrôler et à inclure cette map dans le renderer CheckDataCellRenderer.

    Pensez-vous que cette solution est propre ou avez-vous une solution plus propre ?

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Salut,

    Pour moi une Map est une bonne solution, si les valeurs sont uniques. Si tu utilises un modèle métier (au lieu d'un tableau/vecteur de propriété), tu peux wrapper ton objet dans un objet qui dispose d'une propriété booléenne et l'utiliser pour déterminer si la cellule doit être bordée ou pas, et ainsi ne pas avoir de problématique de gestion de doublon. Tu peux aussi faire un modèle qui wrappe un tableau qui a une colonne de plus avec l'information, mais ça oblige le renderer à avoir une référence sur ce tableau, ce qui est moins élégant.
    Tu peux déléguer la gestion de la bordure à un renderer spécifique (décorateur) ce qui te permet plus facilement le branchement/débranchement et évite de mettre en dur la gestion de la bordure dans le renderer de colonne (si tu en as plusieurs, ça évite aussi la duplication de code).
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 200
    Par défaut
    merci de ta réponse joel, et désolé pour le petit délai de réponse je reviens de weekend

    L'idée d'un modèle métier avec une colonne de plus pour gérer si la cellule doit être bordée ou pas me semble être la meilleure solution, mais dans mon cas il y aurait trop de travail pour mettre en place ce modèle puisque je gère ma Jtable par des colonnes classiques.

    Ce qui ramène à ta deuxième proposition avec le renderer qui contient une référence sur ce tableau. Ca semble un peu moins élégant mais ça convient quand même.
    Par rapport à cette deuxième proposition, il faudrait que je surcharge le modèle de la jtable pour introduire cette nouvelle colonne.
    Mais, est-ce que ça ne reviendrait pas au même de vérifier directement dans le renderer en ajoutant ces 3 conditions : "si ma cellule courante est vide OU que l'une des autres de ma ligne du tableau est vide ALORS je borde ma cellule courante" ?

    Concernant ta dernière remarque joel, pourrais tu me donner une piste pour la gestion de la bordure via un renderer spécifique ? je ne vois pas comment mettre cela en place.

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par bernidupont Voir le message
    Ce qui ramène à ta deuxième proposition avec le renderer qui contient une référence sur ce tableau. Ca semble un peu moins élégant mais ça convient quand même.
    Par rapport à cette deuxième proposition, il faudrait que je surcharge le modèle de la jtable pour introduire cette nouvelle colonne.
    oui

    Citation Envoyé par bernidupont Voir le message
    Mais, est-ce que ça ne reviendrait pas au même de vérifier directement dans le renderer en ajoutant ces 3 conditions : "si ma cellule courante est vide OU que l'une des autres de ma ligne du tableau est vide ALORS je borde ma cellule courante" ?
    Oui, si telle est ta formule (je parlais dans un cas général : stocker l'état évite de recalculer à chaque fois qu'il est nécessaire de faire le rendu, et cela peut être intéressant selon que le calcul soit long ou pas)
    Citation Envoyé par bernidupont Voir le message
    Concernant ta dernière remarque joel, pourrais tu me donner une piste pour la gestion de la bordure via un renderer spécifique ? je ne vois pas comment mettre cela en place.
    Exemple :
    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
    public class JTableRendererDemo {
     
    	public static void main(String[] args) {
     
     
    		JFrame frame = new JFrame("Démo");
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
     
    		frame.add(new JScrollPane(createTable()));
     
    		frame.setSize(600, 400);
    		frame.setLocationRelativeTo(null);
    		frame.setVisible(true);
    	}
     
    	private static JTable createTable() {
     
     
    		TableModel model = new AbstractTableModel() {
     
    			Object[][] data = { 
    						            { 1, "abc", "def", "ghi" },
    						            { 2, null, null, null },
    						            { 3, null, "def", "ghi" }
    							  };
    			String[] columns = { "id", "A", "B", "C" };
     
     
    			@Override
    			public String getColumnName(int col) {
    				return columns[col];
    			}
     
    			@Override
    			public boolean isCellEditable(int row, int col) {
    				return col>0;
    			}
     
    			@Override
    			public Class<?> getColumnClass(int col) { 
    				switch(col) {
    				case 0:
    					return Integer.class;
    				default:
    					return String.class;
    				}
    			}
     
    			@Override
    			public int getColumnCount() {
    				return columns.length;
    			}
     
    			@Override
    			public int getRowCount() {
    				return data.length;
    			}
     
    			@Override
    			public Object getValueAt(int row, int col) {
    				return data[row][col];
    			} 
     
    			@Override
    			public void setValueAt(Object value, int row, int col) {
    				data[row][col]=value; 
    			}
     
     
    		};
     
    		JTable table = new JTable(model);
     
    		TableColumn column = table.getColumnModel().getColumn(2);
    		column.setCellRenderer(new BorderTableCellRenderer(table.getDefaultRenderer(String.class)));
     
    		return table;
    	}
     
    	private static class BorderTableCellRenderer implements TableCellRenderer {
     
    		private final static Border BORDER = BorderFactory.createLineBorder(Color.RED, 2);
     
    		private TableCellRenderer renderer;
     
    		public BorderTableCellRenderer(TableCellRenderer renderer) {
    			this.renderer=renderer;
    		}
     
    		@Override
    		public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
    				int column) {
    			JComponent component = (JComponent)renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    			boolean isnull=true;
    			for(int i=1; i<4; i++) {
    				String valueCol = (String) table.getValueAt(row, i);
    				if ( valueCol!=null && !valueCol.trim().isEmpty() ) {
    					isnull=false;
    					break;
    				}
    			}
    			if ( isnull ) {
    				if ( !hasFocus ) {
    					component.setBorder(BORDER);
    				}
    				else {
    					component.setBorder(BorderFactory.createCompoundBorder(component.getBorder(), BORDER));
    				}
    			}
    			return component;
    		}
     
    	} 
     
    }
    Tu peux même faire
    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
    @Override
    		public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
    				int column) {
    			JComponent component = (JComponent)renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    			boolean isnull=true;
    			for(int i=1; i<4; i++) {
    				String valueCol = (String) table.getValueAt(row, i);
    				if ( valueCol!=null && !valueCol.trim().isEmpty() ) {
    					isnull=false;
    					break;
    				}
    			}
    			if ( isnull ) {
    				component.setBorder(BorderFactory.createCompoundBorder(component.getBorder(), BORDER));
    			}
    			return component;
    		}
    J'hésite entre aimer et ne pas aimer d'un côté, on a pas l'effet de changement/superposition sur la partie bordée due au focus, d'un autre on a une bordure blanche qui fait un peu bizarre, peut être avec un autre type de ligne spéciale, ça passerait mieux, genre comme ça :

    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
    private static class BorderTableCellRenderer implements TableCellRenderer {
     
     
    		private final static BasicStroke STROKE = new BasicStroke(1.0f,
                    BasicStroke.CAP_ROUND,
                    BasicStroke.JOIN_ROUND,
                    0.0f, new float[]{2f,4f}, 0.0f);
    		private final static Border BORDER = BorderFactory.createStrokeBorder(STROKE, Color.RED);
     
    		private TableCellRenderer renderer;
     
    		public BorderTableCellRenderer(TableCellRenderer renderer) {
    			this.renderer=renderer;
    		}
     
    		@Override
    		public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
    				int column) {
    			JComponent component = (JComponent)renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    			boolean isnull=true;
    			for(int i=1; i<4; i++) {
    				String valueCol = (String) table.getValueAt(row, i);
    				if ( valueCol!=null && !valueCol.trim().isEmpty() ) {
    					isnull=false;
    					break;
    				}
    			}
    			if ( isnull ) {
    				component.setBorder(BorderFactory.createCompoundBorder(component.getBorder(), BORDER));
    			}
    			return component;
    		}
     
    	}
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    200
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 200
    Par défaut
    Merci pour ta solution joel, elle est un peu plus propre que celle définit initialement. On se rapproche du purisme là !

    Et par rapport à ma problématique de base, est-ce possible d'activer temporairement le renderer (getTableCellRendererComponent) à la suite d'une action ?
    Par exemple, j'ajoute une ligne dans ma jtable via un bouton "Ajouter". Je saisis les 2 premières colonnes sur les 3 colonnes de ma nouvelle ligne puis je clique sur un bouton "Valider".
    J'aimerais qu'à ce moment là, le renderer s'active et que la 3ème colonne de ma nouvelle ligne, qui est vide, s'affiche avec un border rouge.
    Le renderer (getTableCellRendererComponent) se désactive alors, jusqu'à la prochaine action sur le bouton "Valider".

  6. #6
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Par exemple avec un booléen :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    @Override
    		public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
    				int column) {
    			JComponent component = (JComponent)renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                            if ( disabled ) { // si disabled est true, on retourne directement le renderer standard, sans passer par la partie qui met un cadre rouge...
                                return component;
                            }
    			boolean isnull=true;
    Il te suffit d'avoir une méthode setDisabled() sur la classe BorderTableCellRenderer pour changer la valeur de ce booléen, d'avoir accès à la référence de l'instance pour pouvoir appeler la méthode et activer ou pas le renderer sur l'action que tu veux. Il faudra juste forcer un rafraichissement de la JTable (un updateUI() devrait suffire ou un repaint()), parce qu'elle ne peut pas savoir quand tu changes la valeur ce booléen.

    Une autre solution serait de d'alterner entre les 2 renderers (le BorderTableCelleRenderer et l'instance d'origine) avec l'appel de la méthode column.setCellRenderer();.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

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

Discussions similaires

  1. [XL-2007] exécuter une macro automatiquement après la saisie dans une cellule
    Par Merryy dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 25/07/2015, 23h40
  2. Réponses: 13
    Dernier message: 04/03/2009, 23h05
  3. Réponses: 5
    Dernier message: 03/02/2009, 13h43
  4. Réponses: 2
    Dernier message: 17/11/2008, 12h40
  5. Lancement d'une macro après mise à jour d'une cellule
    Par Mukade dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 17/10/2007, 11h52

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