2015-01-30 27 views
8

Khi tôi đang sử dụng JXTable để hiển thị và chỉnh sửa dữ liệu của mình, một số đầu vào vào CellEditors bị mất. Nếu tôi bấm vào Resizing-Divider của JXTable-ColumnHeader hoặc thay đổi chiều rộng của JFrame, CellEditor sẽ bị chấm dứt mà không cần commit giá trị. Các giá trị được lưu nếu tôi sử dụng JTable.Tại sao JXTable mất đầu vào khi JTable không?

Tôi muốn sử dụng JXTable vì các tính năng khác của nó, vì vậy có cách nào để khắc phục JXTable không?

Screenrecording

Ví dụ:

package table.columnresize; 

import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.table.DefaultTableModel; 

import org.jdesktop.swingx.JXTable; 

/** 
* Demo of differing behaviour of JXTable and JTable. JXTable loses input in a TableCell where JTable persists 
* it. 
* <p> 
* <table border=1> 
* <tr> 
* <th></th> 
* <th>JXTable</th> 
* <th>JTable</th> 
* </tr> 
* <tr> 
* <td>Click on TableColumnHeader</td> 
* <td>saved</td> 
* <td>saved</td> 
* </tr> 
* <tr> 
* <td>Resizing with Divider of TableColumnHeader</td> 
* <td>lost</td> 
* <td>saved</td> 
* </tr> 
* <tr> 
* <td>Changing the width of JFrame</td> 
* <td>lost</td> 
* <td>saved</td> 
* </tr> 
* 
* </table> 
* </p> 
* 
* @author bobndrew 2015-01-29 
*/ 
public class JXTableAndJTableEditLossDemo 
{ 
    private static class DataModel extends DefaultTableModel 
    { 
    public DataModel(Object[][] data, Object[] columnNames) 
    { 
     super(data, columnNames); 
    } 
    } 

    private static void createAndShowUI() 
    { 
    Object[][] DATA = { { "One", 1 }, { "Two", 2 }, { "Three", 3 }, { "Four", 4 }, { "Five", 5 } }; 
    String[] COLUMNS = { "A", "B" }; 
    DataModel dataModel = new DataModel(DATA, COLUMNS); 

    JFrame frame1 = new JFrame("JXTable"); 
    JXTable jXTable = new JXTable(dataModel); 
    //does not change anything: jXTable.setTerminateEditOnFocusLost(true); 
    System.out.println(jXTable.isTerminateEditOnFocusLost()); 
    frame1.add(new JScrollPane(jXTable)); 
    frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame1.pack(); 
    frame1.setVisible(true); 

    JFrame frame2 = new JFrame("JTable"); 
    JTable jTable = new JTable(dataModel); 
    //does not change anything: jTable.putClientProperty("terminateEditOnFocusLost", Boolean.FALSE); 
    System.out.println(jTable.getClientProperty("terminateEditOnFocusLost")); 
    frame2.add(new JScrollPane(jTable)); 
    frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame2.pack(); 
    frame2.setLocation((int) frame1.getLocation().getX() + frame1.getWidth() + 100, (int) frame1 
     .getLocation().getY()); 
    frame2.setVisible(true); 
    } 

    public static void main(String[] args) 
    { 
    java.awt.EventQueue.invokeLater(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
     createAndShowUI(); 
     } 
    }); 
    } 

} 
+0

Bạn đã thử thêm trình xử lý tập trung tùy chỉnh vào JXTable chưa? Xem câu trả lời thứ 2 và thứ 3 trên bài đăng này. http://stackoverflow.com/questions/1652942/can-a-jtable-save-data-whenever-a-cell-loses-focus –

+0

Ý tưởng hay, nhưng một FocusListener quá không đáng tin cậy trong các hệ điều hành khác nhau. – bobndrew

Trả lời

3

Khi gỡ lỗi JXTableJTable Tôi đã tìm thấy lý do mất CellEdits. Sự khác biệt là trong phương pháp columnMarginChanged():

JXTable:

if (isEditing()) { 
    removeEditor(); 
} 

JTable:

if (isEditing() && !getCellEditor().stopCellEditing()) { 
    getCellEditor().cancelCellEditing(); 
} 

Lúc đầu, tôi nghĩ rằng phương pháp removeEditor() là một nâng cao của JTable ... Nhưng sau đó tôi tìm thấy điều này OpenJDK changeset from September 2010 sửa lỗi "4330950: Mất dữ liệu mới được nhập vào ô khi đổi kích thước chiều rộng cột". Dường như các thay đổi từ JDK không được áp dụng cho mã nguồn SwingX.

Tôi sẽ chấp nhận câu trả lời của riêng mình vì lý do hành vi khác nhau hiện đã rõ ràng. Để khắc phục sự cố này cho tôi và những người dùng SwingX khác, tôi sẽ truy cập danh sách gửi thư của SwingX và trình theo dõi lỗi.

1

Khi bạn hãy nhìn vào phương pháp frameInit() của JTable, bạn có thể thấy rằng nó liên kết với tất cả AWTEvent.WINDOW * sự kiện. Trong JXTable phương thức initActionsAndBindings() liên kết với các hành động cụ thể (chẳng hạn như giá trị thay đổi), và chỉ cho bảng.

Bạn sẽ cần phải thêm người nghe của riêng bạn

jXTable.getColumnModel().addColumnModelListener(new TableColumnModelListener() { 
     @Override 
     public void columnMarginChanged(ChangeEvent e) { 

     } 
    }); 

và sau đó sẽ phải tiếp xúc với một số chức năng của bảng để cho phép sự kiện này để kích hoạt cập nhật bàn. Hoặc có lẽ bạn có thể kích hoạt một TableModelEvent từ đó.

+0

'frameInit()' là một phương thức trong 'JFrame.java' và không phải là' JTable.java'. Nhưng ý tưởng của bạn với một 'TableColumnModelListener' và' columnMarginChanged() 'tương tự như những phát hiện của tôi; xem câu trả lời của tôi – bobndrew

Các vấn đề liên quan