2017-10-10 111 views
1

目前,我想要實現我的JTable中的JPopupMenu,允許編輯單元格的使用的TableModel setCellEditable並自動將該值設置爲false

@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()然後返回editableCells [] []數組的值。 但在我的代碼中,當焦點丟失時,應該將單元格更改爲不可編輯?

在一個稍微相關的筆記上,我還想讓單元立即獲得重點。我已閱讀getEditorComponent().requestFocus() - 但這看起來並不完全正確,因爲當時沒有編輯任何內容,只選擇單元格(並且使用該方法引發似乎支持我的思考過程的nullpointerexception)。

任何人都可以指出我正確的方向嗎?我看不到我要去哪裏錯了。由於

**編輯:爲了鎖定細胞丟失焦點時我嘗試添加自定義CellRenderer與focusListener的:

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

道歉長度 - 我不知道如何使它無需重新創建也許什麼不好,我想實現更短。在這個代碼中有一個錯誤,那就是右鍵單擊和'解鎖',你必須已經左鍵單擊一行,否則它們將是一個arrayIndexOutOfBounds異常。我還沒有找到確切的原因。

但基本上,當你右鍵單擊然後選擇解鎖,我想光標出現在單元格中。此時您單擊解鎖,然後必須雙擊單元格。

+0

渲染器不是真正的組件。它只是用來繪製組件的圖像。它永遠不會成爲焦點。不要使用「==」來比較字符串。使用'equals(...)'方法。發佈一個證明問題的適當的[mcve]。 – camickr

+0

對不起,它不是那麼簡單,但我已經發布了一個完整的工作示例,並描述了我想要實現的內容。 – NickW

回答

0

但是在我的代碼中,當焦點丟失時應該將單元格更改爲不可編輯? -

,你可以:

  1. 覆蓋你的TableModel的setValueAt(...)方法,使細胞無法修改,一旦數據被改變。

  2. 使用a TableModelListener它會在單元格的數據更新時生成一個事件。

+0

謝謝。把它放在setValueAt()中是完美的,非常感謝。 setCellEditable()儘管調用了fireTableCellUpdated(),所以我不認爲我可以在沒有無限循環的情況下將它放在那裏,但是我明白,如果沒有SSCCE,您可能無法評論。無論如何它現在工作,所以再次感謝。 – NickW

+0

就在我回答這個問題之前 - 關於如何立即讓單元格可編輯的任何想法?即我右鍵單擊單元格,選擇'解鎖',並且光標在那裏。而不必在之後再次雙擊。如果有幫助,我可以創建一個SSCCE,但即使你只是有一個模糊的方向指向我也會有所幫助。 – NickW

+0

@NickW,'setCellEditable()調用fireTableCellUpdated()雖然 - 它不應該調用任何fireXXX()方法,因爲單元格中的數據沒有改變。 – camickr

相關問題