2009-02-19 8 views
8

Tôi có nhiều trình chỉnh sửa tùy chỉnh cho một JTable và không thể nói rằng khả năng sử dụng, đặc biệt liên quan đến chỉnh sửa bằng bàn phím, thiếu.JTable với trình chỉnh sửa phức tạp

Lý do chính của việc này là biên tập viên của tôi luôn tạo ra với một (mặc dù thường phức tạp hơn) tình hình tương tự như sau:

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

tức là một bảng điều khiển với nhiều hơn một thành phần bên trong. Trình soạn thảo văn bản thực tế là một hậu duệ của thành phần được trả về làm trình soạn thảo. Vì vậy, hiển thị các vấn đề sang một bên, từ những gì tôi có thể nói, JTable đang tập trung thành phần được trả về theo phương pháp getTableCellEditorComponent. biên tập viên.
Có anyway tôi có thể thông báo cho JTable rằng trình biên tập "thực sự" là JTextfield không? Thêm hacky requestFocusInWindow vào thành phần chính xác không đủ khi nhấn phím sẽ không được truyền.

Trả lời

4

Kiểm tra một số bài viết có liên quan herehere.

Một good article khác về chỉnh sửa JTable nói chung.

+0

Có, cảm ơn. Tôi chỉ có một số lời khuyên tương tự trên diễn đàn mặt trời. http://forums.sun.com/thread.jspa?threadID=5368525 –

2

Nếu tôi đọc chính xác câu hỏi của bạn, bạn muốn người dùng có thể nhập vào ô ngay lập tức, mà không cần kích hoạt trình chỉnh sửa ô trước, tức là bạn muốn bất kỳ phím nào được kích hoạt trong ô là ký tự đầu tiên được nhập vào văn bản cánh đồng.

Nỗ lực đầu tiên của tôi là thêm thuộc tínhChangeListener trên thuộc tính focusTwner của KeyboardFocusManager, chỉ để thông báo rằng tiêu điểm không bao giờ rời khỏi JTable. Bạn có thể chạy vào đó là tốt. Thời gian cho kế hoạch B.

Tôi nhận được điều "nhấn phím đầu tiên" để làm việc bằng cách thêm một KeyListener vào bảng ghi KeyEvent cuối cùng cho phương thức keyPressed() trong một trường cá thể. Phương thức getTableCellEditorComponent() đọc ký tự từ đó. Tôi cũng cần rằng yêu cầu hackFocusInWindow() gọi bạn đề cập đến nếu người dùng tiếp tục gõ bất kỳ ký tự nào sau lần đầu tiên.

Đối với ứng dụng mẫu của mình, tôi đã tạo một lớp con của JTable để thêm KeyListener vào chính nó. Đó là một ý tưởng tốt hơn để làm cho cá thể CellEditor của bạn triển khai KeyListener và thêm nó vào JTable thông thường thay vào đó, nhưng tôi sẽ để nó cho bạn.

Dưới đây là đoạn mã của bạn như tôi sửa đổi nó:

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

As far as nastiness đi này ngồi ở đâu đó lên đó với Vogon thơ, nhưng nó phải giải quyết vấn đề trước mắt của bạn.

+0

Cảm ơn câu trả lời. Chúng tôi đã thực hiện điều này một cách hiệu quả (theo các cách khác nhau cho các trình chỉnh sửa khác nhau) và nó đưa chúng ta vào tất cả các loại sự cố (ví dụ: trình chỉnh sửa được kích hoạt bởi chuột và trình nghe khóa bảng vẫn có lastKeyPressed). Loại tìm kiếm một giải pháp đẹp hơn. –

+0

Tôi đã xem xét kỹ hơn một chút, và cuối cùng đã kết thúc ở lớp bên trong Handler trong BasicTableUI. Không có mẫu mã nào được nêu ra. – Barend

0

tôi cố định một cái gì đó tương tự trong 2 bước

Đầu ghi đè editCellAt từ JTable của bạn và gọi requestFocus sau khi chuẩn bị biên tập:

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

Sau đó, quá tải requestFocus từ JPanel của bạn và chắc chắn rằng textfield của bạn là đặt làm editorComponent:

public class EditorPanel extends JPanel { 
    JComponent editorComponent; 

    public boolean isRequestFocusEnabled() 
    { 
    return true; 
    } 

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

Bạn luôn có thể lấy keyEvent và tự thiết lập:

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

Vâng, tôi đã thử phương pháp này trước đây. Tôi đã thử nó trên mã của tôi và, như tôi mong đợi, bấm phím đầu tiên kích hoạt trình chỉnh sửa sẽ không được truyền (vì nó khi bạn đang sử dụng một trường chỉnh sửa đơn giản) tức là nếu bạn tab vào ô và nhấn "123 "chỉ" 23 "xuất hiện trong thành phần. –

0

Tôi nghĩ rằng tôi đã giải quyết nó.
Để cho bạn biết sự thật, tôi không biết điều gì đã giải quyết được vấn đề, vì tôi đang sử dụng trình chỉnh sửa tùy chỉnh, trình kết xuất tùy chỉnh và nội dung ...

Khi ô được tô sáng và tôi nhấn "abc" , 3 chữ cái xuất hiện trên màn hình (trong trường hợp này).

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

Vâng ... Tôi cố gắng ... =)
(Tôi không biết nếu đó là cùng vì JTable của tôi sử dụng JTextField và JComboBox như biên tập viên).

0

Tôi gặp vấn đề tương tự. Trong trường hợp của tôi, tôi đã phức tạp TableCellEditor bao gồm JSpinner và một số thành phần khác. Vấn đề là khi biên tập viên bắt đầu, tôi muốn chuyển trọng tâm vào thành phần bên trong của nó. Tôi đã sửa lỗi này bằng cách gọi số panel.transferFocusDownCycle() nhưng điều này lại khiến các sự kiện bàn phím ngừng hoạt động - khi thành phần nội bộ của tôi có tiêu điểm và tôi nhấn phím, tôi mong đợi thành phần đó sẽ chặn sự kiện này và thay đổi giá trị của nó. Thay vào đó, bảng đã thay đổi tiêu điểm thành một ở trên ... Tôi đã sửa lỗi này bằng cách thêm KeyListener và gửi tất cả các sự kiện chính trực tiếp đến thành phần bên trong.

Đây là lớp trình bao bọc dựa trên JPanel Tôi đã viết để làm cho cuộc sống của tôi dễ dàng hơn.

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) { 
    } 
}