2009-02-19 32 views
8

我有許多JTable的自定義編輯器,這是一個輕描淡寫的說可用性,特別是關於編輯鍵盤,缺乏。JTable與一個複雜的編輯器

主要的原因是我的編輯始終具有相似(雖然往往更復雜)的情況創建這樣的:

@Override 
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { 
    JPanel container = new JPanel(); 
    container.setLayout(new BorderLayout()); 
    container.add(field, BorderLayout.CENTER); 
    field.setText((String) value); 
    container.add(new JButton("..."), BorderLayout.EAST); 
    return container; 
} 

即與內部多個組件的面板。實際的文本編輯器是作爲編輯器返回的組件的後代。 因此,從我所知道的問題來看,JTable正在關注由getTableCellEditorComponent方法返回的組件,因此當您按下一個突出顯示的單元格的按鍵時,它將焦點和按鍵按下到面板上,認爲這是編輯。
反正我可以通知JTable「真實」編輯器是JTextfield嗎? 在正確的組件上添加hacky requestFocusInWindow是不夠的,因爲按鍵不會傳遞。

回答

2

如果我正確地閱讀了您的問題,您希望用戶能夠立即鍵入到單元格中,而無需先激活單元格編輯器,即您希望任何按鍵激活單元格作爲輸入到文本中的第一個字符領域。

我的第一次嘗試是在KeyboardFocusManager的focusOwner屬性上添加一個propertyChangeListener,只注意焦點從不離開JTable。你可能也遇到過這種情況。計劃B的時間。

通過將KeyListener添加到記錄實例字段中keyPressed()方法的最後一個KeyEvent的表中,我得到了「第一個按鍵」的工作。 getTableCellEditorComponent()方法從那裏讀取字符。我還需要這個hacky requestFocusInWindow()調用你提到用戶是否繼續在第一個字符後輸入任何字符。

對於我的示例應用程序,我創建了一個JTable的子類,它爲自己添加了一個KeyListener。將CellEditor實例實現爲KeyListener並將其添加到常規JTable是一個好主意,但我會將其留給您。

這裏是你的代碼片段,我修改了它:

@Override 
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { 
    JPanel container = new JPanel(); 
    container.setLayout(new BorderLayout()); 
    container.add(field, BorderLayout.CENTER); 

    // Will want to add an instanceof check as well as a check on Character.isLetterOrDigit(char). 
    char keypressed = ((StickyKeypressTable)table).getLastKeyPressed(); 
    field.setText(String.valueOf(keypressed)); 

    container.add(new JButton("..."), BorderLayout.EAST); 

    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      // This needs to be in an invokeLater() to work properly 
      field.requestFocusInWindow(); 
     } 
    }); 
    return container; 
} 

至於污穢去這個地方坐那裏與沃貢詩,但它應該解決您的眼前的問題。

+0

感謝您的回答。一段時間以來,我們一直在這樣做(對不同的編輯者以不同的方式),這讓我們陷入了各種各樣的麻煩中(例如編輯器被鼠標激活並且表鍵控偵聽器仍然有一個lastKeyPressed)。一種尋找更好的解決方案。 – 2009-02-19 19:22:40

+0

我一直在進一步研究它,最終結果在內部類BasicTableUI。儘管沒有代碼示例。 – Barend 2009-02-19 20:11:03

0

我固定的類似的東西在2個步驟

首先從您的JTable覆蓋editCellAt和準備編輯器之後,調用requestFocus的:

public boolean editCellAt(int row, int column, EventObject e) 
{ 
    if (cellEditor != null && !cellEditor.stopCellEditing()) 
    { 
    return false; 
    } 

    if (row < 0 || row >= getRowCount() || 
     column < 0 || column >= getColumnCount()) 
    { 
    return false; 
    } 

    if (!isCellEditable(row, column)) 
    return false; 

    TableCellEditor editor=getCellEditor(row, column); 
    if (editor != null && editor.isCellEditable(e)) 
    { 
    editorComp=prepareEditor(editor, row, column); 
    if (editorComp == null) 
     { 
     removeEditor(); 
     return false; 
     } 
    //aangepast 
    Rectangle rect=getCellRect(row, column, false); 
    if (datamodel_.useAdaptedEditorRect()) 
     rect=datamodel_.changeRectangle(rect, editorComp); 
    editorComp.setBounds(rect); 
    add(editorComp); 
    editorComp.validate(); 

    setCellEditor(editor); 
    setEditingRow(row); 
    setEditingColumn(column); 
    editor.addCellEditorListener(this); 
    //NEXT LINE ADDED 
    editorComp.requestFocus(); 
    return true; 
    } 
    return false; 
} 

然後從你的JPanel超載requestFocus的,並確保您的文本字段是把儘可能editorComponent:

public class EditorPanel extends JPanel { 
    JComponent editorComponent; 

    public boolean isRequestFocusEnabled() 
    { 
    return true; 
    } 

    public void requestFocus() 
    { 
    editorComponent.requestFocus(); 
    } 
} 

你總是可以抓住的keyEvent和自己設置它:

AWTEvent event = EventQueue.getCurrentEvent(); 
if (event instanceof KeyEvent) 
    { 
    char newSelection = ((KeyEvent) event).getKeyChar(); 
    int keyCode = ((KeyEvent) event).getKeyCode(); 
    editorComponent.requestFocus(); 
    if (editorComponent instanceof JTextField) 
    { 
    if ((newSelection >= (char) FIRST_ALLOWED_CHAR) && (newSelection != (char) LAST_ALLOWED_CHAR)) //comes from DefaultKeyTypedAction 
     ((JTextField) editorComponent).setText(Character.toString(newSelection)); 
    if (keyCode == KeyEvent.VK_BACK_SPACE || keyCode == KeyEvent.VK_DELETE) 
     ((JTextField) editorComponent).setText("");   
    } 
    } 
else 
    editorComponent.requestFocus(); 
+0

是的,我已經嘗試過這種方法。我試了我的代碼,並且,正如我所料,激活編輯器的第一次按鍵不會被傳遞(就像它使用簡單的編輯字段時那樣),即如果您選中該單元格並點擊「123 「只有」23「出現在組件中。 – 2009-02-20 12:18:40

0

我想我解決了它。
要告訴你實話,我不知道是什麼的問題解決了,因爲我使用的是自定義編輯器,自定義渲染器和東西...

當細胞被突出顯示,我按下「ABC」 ,3個字母在屏幕上顯示(在這種情況下爲單元格)。

grid.addKeyListener(new KeyAdapter() { 
    public void keyTyped(KeyEvent ke) { 
     int l = grid.getSelectedRow(); 
     int c = grid.getSelectedColumn(); 
     grid.editCellAt(l, c); 
    } 
}); 

嗯...我想... =)
(我不知道這是否是相同的,因爲我的JTable使用的JTextField和JComboBox爲編輯)。

0

我有非常類似的問題。在我的情況下,我有複雜的TableCellEditor,它由JSpinner和一些其他組件組成。問題在於,當單元編輯器開始時,我想將焦點轉移到其內部組件。我通過調用panel.transferFocusDownCycle()來解決這個問題,但這又導致鍵盤事件停止工作 - 當我的內部組件有焦點並且按下鍵時,我期待該組件將攔截此事件並更改其值。相反,表格將行焦點更改爲上面的一個......我通過添加KeyListener並將所有關鍵事件直接分派給內部組件來解決此問題。

這是基於JPanel的包裝類,是爲了讓我的生活更輕鬆。

public class ContainerPanel extends JPanel implements KeyListener, FocusListener { 

    private JComponent component = null; 

    public ContainerPanel(JComponent component) { 
     this.component = component; 
     addKeyListener(this); 
     addFocusListener(this); 
     setFocusCycleRoot(true); 
     setFocusTraversalPolicy(new ContainerOrderFocusTraversalPolicy()); 
     add(component); 
    } 

    @Override 
    public void keyTyped(KeyEvent e) { 
     component.dispatchEvent(e); 
    } 

    @Override 
    public void keyPressed(KeyEvent e) { 
     component.dispatchEvent(e); 
    } 

    @Override 
    public void keyReleased(KeyEvent e) { 
     component.dispatchEvent(e); 
    } 

    @Override 
    public void focusGained(FocusEvent e) { 
     component.transferFocusDownCycle(); 
    } 

    @Override 
    public void focusLost(FocusEvent e) { 
    } 
}