2017-10-10 8 views
1

Je tente actuellement de mettre en œuvre un JPopupMenu dans mon JTable qui permet le déblocage d'une cellule pour le montage en utilisantTableModel setCellEditable et réglage automatique de la valeur à false

@Override 
public void actionPerformed(ActionEvent e){ 
    if(e.getActionCommand() == "Unlock"){ 
     pTableModel.setCellEditable(this.getSelectedRow(), this.getSelectedColumn(), true); 
    } 
} 

Cette méthode est associée dans le TableModel

public void setCellEditable(int row, int col, boolean value) { 
    editableCells[row][col] = value; 
    this.fireTableCellUpdated(row, col); // I don't think I actually need this 
             //because nothing in the cell has changed yet? 
} 

isCellEditable() retourne alors la valeur de la matrice editableCells [] []. mais où dans mon code devrais-je changer la cellule à inédite lorsque le focus est perdu?

Sur une note légèrement liée, je voudrais également que la cellule gagne immédiatement le focus. J'ai lu à propos de getEditorComponent().requestFocus() - mais cela ne semble pas tout à fait correct car rien n'est édité à ce moment-là, la cellule est seulement sélectionnée (et en utilisant cette méthode jette une nullpointerexception qui semblerait soutenir mon processus de pensée).

Quelqu'un peut-il me diriger dans la bonne direction s'il vous plaît? Je ne peux pas voir où je vais mal. Merci

** Edit: Pour verrouiller la cellule lorsque le focus est perdu, j'ai essayé d'ajouter une CellRenderer personnalisée avec une focusListener:

private class CustomCellRenderer extends DefaultTableCellRenderer{ 
    public CustomCellRenderer(){ 
     addFocusListener(new FocusAdapter(){ 
      @Override 
      public void focusLost(FocusEvent e) { 
       pTableModel.setCellEditable(getSelectedRow(), getSelectedColumn(), false); 

      } 
     }); 
    } 
} 

mais cela n'a pas semblé fonctionner non plus, mais je suis sans doute la mise en œuvre incorrectement (même si je l'ai vérifié que le moteur de rendu a été ajouté)


SSCCE

import java.awt.event.*; 
import java.util.*; 
import javax.swing.*; 
import javax.swing.table.AbstractTableModel; 

public class CellTest {  
    public static void main(String[] args){ 
     SwingUtilities.invokeLater(new Runnable(){ 
      @Override 
      public void run(){ 
       createAndShowGUI(); 
      } 
     }); 
    } 
    private static void createAndShowGUI(){ 
     JFrame f = new JFrame(); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     MyPanel panel = new MyPanel(); 

     f.add(panel); 
     f.pack(); 
     f.setVisible(true); 
    } 
} 


class MyPanel extends JPanel implements ActionListener{ 
    private JTable table; 
    private MyTableModel model; 
    private JScrollPane sp; 
    private List<Person> people; 

    MyPanel(){ 
     people = new ArrayList<>(); 
     people.add(new Person("Will", 1)); 
     model = new MyTableModel(people); 

     table = new JTable(model); 
     table.addMouseListener(new MouseAdapter(){ 
      @Override 
      public void mousePressed(MouseEvent e){ 
       maybeShowPopup(e); 
      } 
      @Override 
      public void mouseReleased(MouseEvent e){ 
       maybeShowPopup(e); 
      } 
     }); 

     table.setFillsViewportHeight(true); 
     sp = new JScrollPane(table); 
     this.add(sp); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e){ 
     if(e.getActionCommand().equals("Unlock")) { 
       model.setCellEditable(table.getSelectedRow(),table.getSelectedColumn(),true); 
     } 
    } 

    private JPopupMenu createPopupMenu(){ 
     JPopupMenu pop = new JPopupMenu(); 
     JMenuItem item = new JMenuItem("Unlock"); 
     item.addActionListener(this); 
     pop.add(item); 
     return pop; 
    } 

    private void maybeShowPopup(MouseEvent e){ 
     int currentRow = table.rowAtPoint(e.getPoint()); 
     if(currentRow >= 0 && currentRow < table.getRowCount()) 
      table.setRowSelectionInterval(currentRow, currentRow); 
     else 
      table.clearSelection(); 

     if(table.getSelectedRow() < 0) return; 
     if(e.isPopupTrigger() && e.getComponent() instanceof JTable){ 
      JPopupMenu pop = createPopupMenu(); 
      pop.show(e.getComponent(), e.getX(), e.getY()); 
     } 
    } 
} 

Et la TableModel et la classe de données:

class MyTableModel extends AbstractTableModel{ 
    private List<Person> data; 
    private String[] colNames = new String[]{"Name","Age"}; 
    private boolean[][] editableCells; 

    public MyTableModel(List<Person> data){ 
     this.data = data; 
     this.editableCells = new boolean[this.getRowCount()][this.getColumnCount()]; 
    } 

    @Override 
    public int getRowCount() { return data.size(); } 

    @Override 
    public int getColumnCount() { return colNames.length; } 

    @Override 
    public Object getValueAt(int row, int col){ 
     Person p = data.get(row); 
     switch(col){ 
      case 0 : return p.getName(); 
      case 1 : return p.getAge(); 
     } 
     return null; 
    } 

    @Override 
    public boolean isCellEditable(int row, int col){ 
     return editableCells[row][col]; 
    } 

    public void setCellEditable(int row, int col, boolean value){ 
     editableCells[row][col] = value; 
    } 

    @Override 
    public void setValueAt(Object value, int row, int col){ 
     Person p = data.get(row); 
     switch(col){ 
      case 0 : p.setName((String)value);break; 
      case 1 : p.setAge((int)value);break; 
     } 
     this.setCellEditable(row, col, false); 
     this.fireTableCellUpdated(row, col); 
    } 

    public void setData(List<Person> data){ 
     this.data = data; 
     this.fireTableDataChanged(); 
    } 
} 

class Person { 
    private String name; 
    private int age; 

    public Person(String name, int age){ 
     this.name = name; 
     this.age = age; 
    } 

    public void setName(String name){ this.name = name;} 
    public String getName(){ return name; } 
    public void setAge(int age){ this.age = age;} 
    public int getAge(){ return age; } 
} 

Toutes mes excuses pour la longueur - je ne savais pas comment faire plus court, sans peut-être recréer mal ce que je voulais réaliser. Il y a une erreur dans ce code en ce que pour faire un clic droit et "Déverrouiller", vous devez avoir déjà cliqué sur une ligne, sinon il s'agira d'une exception arrayIndexOutOfBounds. Je n'ai pas encore trouvé la cause exacte.

Mais fondamentalement, lorsque vous faites un clic droit, puis sélectionnez déverrouiller, j'aimerais que le curseur apparaisse dans la cellule. Au moment où vous cliquez sur déverrouiller, puis double-cliquez sur la cellule.

+0

Un moteur de rendu n'est pas un composant réel. Il est juste utilisé pour peindre une image d'un composant. Il ne sera jamais mis au point. N'utilisez pas "==" pour comparer des chaînes. Utilisez la méthode 'equals (...)'. Publier un [mcve] approprié qui démontre le problème. – camickr

+0

Désolé, ce n'est pas si minime, mais j'ai posté un exemple complet avec une description de ce que j'essaie d'atteindre. – NickW

Répondre

0

mais où dans mon code devrais-je changer la cellule à non modifiable lorsque le focus est perdu? -

Vous pouvez:

  1. override la méthode setValueAt(...) de votre TableModel pour faire une cellule non modifiable une fois les données sont modifiées.

  2. utilise un TableModelListener Il génère un événement lorsque les données d'une cellule sont mises à jour.

+0

merci. le mettre dans setValueAt() fonctionne parfaitement, très apprécié. Cependant, setCellEditable() appelle fireTableCellUpdated(), donc je ne pense pas que je puisse le mettre dedans sans une boucle infinie, mais je comprends que sans SSCCE vous ne pouvez probablement pas commenter. De toute façon, ça fonctionne maintenant, alors merci encore. – NickW

+0

juste avant que je marque cette réponse - des idées sur la façon dont je devrais approcher rendre la cellule éditable immédiatement? c'est-à-dire que je fais un clic droit sur la cellule, sélectionne 'déverrouiller', et le curseur est là. plutôt que de devoir ensuite double-cliquer à nouveau après. Je peux faire un SSCCE si cela peut aider, mais même si vous avez juste une vague direction pour me pointer dedans, cela aiderait. – NickW

+0

@NickW, 'setCellEditable() appelle fireTableCellUpdated() though' - il ne devrait pas appeler de méthode fireXXX(), car les données de la cellule n'ont pas changé. – camickr