2017-10-10 1 views
1

Einstellung Ich versuche zur Zeit eine JPopupMenu in meinem JTable zu implementieren, die die Entriegelung einer Zelle für die Bearbeitung ermöglicht mitTablemodel setCellEditable und automatisch den Wert zurück auf false

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

Dies ist ein verwandtes Verfahren in dem 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() gibt dann den Wert des editableCells [] [] Array. Aber wo in meinem Code sollte ich die Zelle zurück zu uneditable ändern, wenn der Fokus verloren geht?

Zu einer etwas verwandten Anmerkung möchte ich auch, dass die Zelle sofort den Fokus erhält. Ich habe über getEditorComponent().requestFocus() gelesen - aber das scheint nicht ganz richtig zu sein, weil zu dieser Zeit nichts bearbeitet wird, die Zelle wird nur ausgewählt (und die Verwendung dieser Methode löst eine Null-Null-Wahrnehmung aus, die meinen Denkprozess zu unterstützen scheint).

Kann mir bitte jemand in die richtige Richtung zeigen? Ich kann nicht sehen, wo ich falsch liege.

Dank

** Edit: Für die Zelle zu verriegeln, wenn Fokus verloren habe ich versucht, eine benutzerdefinierte Zellrenderer mit einem focuslistener Zusatz:

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

      } 
     }); 
    } 
} 

aber das scheint nicht zu funktionieren, aber ich bin wahrscheinlich die Umsetzung es falsch (obwohl ich überprüft haben, dass der Renderer hinzugefügt wurde)


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()); 
     } 
    } 
} 

Und das Tablemodel und Datenklasse:

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; } 
} 

Apologies für die Länge - ich wusste nicht, wie es kürzer zu machen, ohne vielleicht schlecht neu zu erstellen, was ich erreichen wollte. In diesem Code liegt ein Fehler darin, dass Sie mit der rechten Maustaste und der Schaltfläche "Entsperren" auf eine Zeile bereits geklickt haben müssen, da es sich andernfalls um eine arrayIndexOutOfBounds-Ausnahme handelt. Ich konnte die genaue Ursache noch nicht finden.

Aber im Grunde, wenn Sie mit der rechten Maustaste klicken und dann Entsperren auswählen, möchte ich den Cursor in der Zelle angezeigt werden. In dem Moment klicken Sie auf Entsperren und müssen dann auf die Zelle doppelklicken.

+0

Ein Renderer ist keine echte Komponente. Es wird nur verwendet, um ein Bild einer Komponente zu zeichnen. Es wird nie den Fokus bekommen. Verwenden Sie nicht "==", um Strings zu vergleichen. Verwenden Sie die 'equals (...)' Methode. Veröffentlichen Sie eine ordnungsgemäße [mcve], die das Problem veranschaulicht. – camickr

+0

Entschuldigung, es ist nicht so minimal, aber ich habe ein voll funktionierendes Beispiel mit einer Beschreibung dessen, was ich erreichen möchte, gepostet. – NickW

Antwort

0

aber wo in meinem Code soll ich die Zelle wieder ändern zu uneditable, wenn der Fokus verloren geht? -

Sie könnten:

  1. Überschreibung der setValueAt(...) Methode Ihrer Tablemodel eine Zelle nicht bearbeitbar zu machen, sobald die Daten geändert werden.

  2. Verwenden Sie eine TableModelListener Es wird ein Ereignis generiert, wenn die Daten einer Zelle aktualisiert werden.

+0

danke. Putting in SetValueAt() funktioniert perfekt, sehr geschätzt. setCellEditable() ruft fireTableCellUpdated() auf, daher glaube ich nicht, dass ich es ohne Endlosschleife einfügen kann, aber ich verstehe, dass Sie ohne SSCCE wahrscheinlich keinen Kommentar abgeben können. Entweder funktioniert es jetzt, also danke nochmal. – NickW

+0

kurz bevor ich dies beantworte - irgendwelche Ideen wie ich die Zelle sofort editierbar machen könnte? Dh ich klicke mit der rechten Maustaste auf die Zelle, wähle 'entsperren' und der Cursor ist da. anstatt danach nochmal zu doppelklicken. Ich kann eine SSCCE machen, wenn das hilft, aber selbst wenn du nur eine vage Richtung hast, mir zu zeigen, würde dir helfen. – NickW

+0

@NickW, 'setCellEditable() ruft fireTableCellUpdated() though' auf - es sollte keine fireXXX() - Methode aufrufen, da sich die Daten in der Zelle nicht geändert haben. – camickr

Verwandte Themen