columnas - setmodel java
TableModel setCellEditable y configurando automáticamente el valor de nuevo en falso (1)
pero, ¿en qué parte de mi código debería cambiar la celda a no editable cuando se pierde el foco? -
Tú podrías:
anula el
setValueAt(...)
de su TableModel para que una celda no sea editable una vez que se modifican los datos.use
TableModelListener
un evento cuando se actualicen los datos de una celda.
Actualmente estoy tratando de implementar un JPopupMenu en mi JTable que permite desbloquear una celda para editar usando
@Override
public void actionPerformed(ActionEvent e){
if(e.getActionCommand() == "Unlock"){
pTableModel.setCellEditable(this.getSelectedRow(), this.getSelectedColumn(), true);
}
}
Este es el método relacionado en 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()
luego devuelve el valor de la matriz editableCells [] []. pero, ¿en qué parte de mi código debería cambiar la celda a no editable cuando se pierde el foco?
En una nota ligeramente relacionada, también me gustaría que la célula se enfoque inmediatamente. He leído sobre getEditorComponent().requestFocus()
- pero eso no parece del todo correcto porque no se está editando nada en ese momento, la celda solo está seleccionada (y el uso de ese método arroja una nullpointereception que parece apoyar mi pensamiento proceso).
¿Puede alguien señalarme en la dirección correcta, por favor? No puedo ver dónde me estoy equivocando. Gracias
** Editar: para bloquear la celda cuando se pierde el foco intenté agregar un dispositivo celular personalizado con un focusListener:
private class CustomCellRenderer extends DefaultTableCellRenderer{
public CustomCellRenderer(){
addFocusListener(new FocusAdapter(){
@Override
public void focusLost(FocusEvent e) {
pTableModel.setCellEditable(getSelectedRow(), getSelectedColumn(), false);
}
});
}
}
pero eso tampoco parece haber funcionado, pero probablemente lo estoy implementando incorrectamente (aunque he comprobado que se ha agregado el renderizador)
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());
}
}
}
Y el TableModel y la clase de datos:
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; }
}
Disculpas por la duración: no sabía cómo acortarlo sin quizás recrear lo que quería lograr. Hay un error en este código porque al hacer clic con el botón derecho y ''Desbloquear'' debe haber hecho ya clic en una fila, de lo contrario será una excepción arrayIndexOutOfBounds. Todavía no he podido encontrar la causa exacta.
Pero básicamente cuando haces clic derecho y luego seleccionas desbloquear, me gustaría que el cursor aparezca en la celda. En este momento, haga clic en desbloquear y luego haga doble clic en la celda.