TableModel setCellEditable 并自动将值设置回 false
TableModel setCellEditable and automatically setting the value back to false
我目前正在尝试在我的 JTable 中实现一个 JPopupMenu,它允许使用
解锁单元格进行编辑
@Override
public void actionPerformed(ActionEvent e){
if(e.getActionCommand() == "Unlock"){
pTableModel.setCellEditable(this.getSelectedRow(), this.getSelectedColumn(), true);
}
}
这是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()
然后 returns editableCells[][] 数组的值。
但是当失去焦点时,我应该在我的代码中的哪个位置将单元格改回不可编辑状态?
稍微相关一点,我还想让单元格立即获得焦点。我读过 getEditorComponent().requestFocus()
- 但这似乎不太正确,因为当时没有任何内容被编辑,单元格仅被 selected (并且使用该方法抛出 nullpointerexception 这似乎支持我的思考过程)。
有人能指出我正确的方向吗?我看不出哪里错了。谢谢
**编辑:为了在失去焦点时锁定单元格,我尝试添加一个带有 focusListener 的自定义 cellrenderer:
private class CustomCellRenderer extends DefaultTableCellRenderer{
public CustomCellRenderer(){
addFocusListener(new FocusAdapter(){
@Override
public void focusLost(FocusEvent e) {
pTableModel.setCellEditable(getSelectedRow(), getSelectedColumn(), false);
}
});
}
}
但这似乎也不起作用,但我可能实施不正确(虽然我已经检查过渲染器已添加)
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());
}
}
}
以及 TableModel 和数据 class:
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; }
}
对长度表示歉意 - 我不知道如何缩短它,而不会糟糕地重新创建我想要实现的目标。此代码中存在一个错误,即要右键单击并且 'Unlock' 您必须已经左键单击了一行,否则它们将是 arrayIndexOutOfBounds 异常。我还没有找到确切的原因。
但基本上当您右键单击然后 select 解锁时,我希望光标出现在单元格中。此时您单击解锁,然后必须双击该单元格。
but where in my code should I change the cell back to uneditable when focus is lost? -
你可以:
覆盖 TableModel 的 setValueAt(...)
方法,使单元格在数据更改后不可编辑。
使用一个TableModelListener
它会在某个单元格的数据更新时产生一个事件。
我目前正在尝试在我的 JTable 中实现一个 JPopupMenu,它允许使用
解锁单元格进行编辑@Override
public void actionPerformed(ActionEvent e){
if(e.getActionCommand() == "Unlock"){
pTableModel.setCellEditable(this.getSelectedRow(), this.getSelectedColumn(), true);
}
}
这是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()
然后 returns editableCells[][] 数组的值。
但是当失去焦点时,我应该在我的代码中的哪个位置将单元格改回不可编辑状态?
稍微相关一点,我还想让单元格立即获得焦点。我读过 getEditorComponent().requestFocus()
- 但这似乎不太正确,因为当时没有任何内容被编辑,单元格仅被 selected (并且使用该方法抛出 nullpointerexception 这似乎支持我的思考过程)。
有人能指出我正确的方向吗?我看不出哪里错了。谢谢
**编辑:为了在失去焦点时锁定单元格,我尝试添加一个带有 focusListener 的自定义 cellrenderer:
private class CustomCellRenderer extends DefaultTableCellRenderer{
public CustomCellRenderer(){
addFocusListener(new FocusAdapter(){
@Override
public void focusLost(FocusEvent e) {
pTableModel.setCellEditable(getSelectedRow(), getSelectedColumn(), false);
}
});
}
}
但这似乎也不起作用,但我可能实施不正确(虽然我已经检查过渲染器已添加)
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());
}
}
}
以及 TableModel 和数据 class:
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; }
}
对长度表示歉意 - 我不知道如何缩短它,而不会糟糕地重新创建我想要实现的目标。此代码中存在一个错误,即要右键单击并且 'Unlock' 您必须已经左键单击了一行,否则它们将是 arrayIndexOutOfBounds 异常。我还没有找到确切的原因。
但基本上当您右键单击然后 select 解锁时,我希望光标出现在单元格中。此时您单击解锁,然后必须双击该单元格。
but where in my code should I change the cell back to uneditable when focus is lost? -
你可以:
覆盖 TableModel 的
setValueAt(...)
方法,使单元格在数据更改后不可编辑。使用一个
TableModelListener
它会在某个单元格的数据更新时产生一个事件。