2010-01-29 22 views
11

Làm cách nào để phát hiện hành động di chuyển cột được hoàn thành trong JTable? Tôi đã thêm columnModeListener vào mô hình cột của tôi nhưng vấn đề là phương thức columnMoved được gọi mỗi khi một cột di chuyển (theo một số pixel nhất định). Tôi không muốn hành vi này. Tôi chỉ muốn phát hiện khi kéo cột xong.Cột đã di chuyển [đã hoàn thành] sự kiện trong JTable

columnModel.addColumnModelListener(new TableColumnModelListener() { 

      public void columnAdded(TableColumnModelEvent e) { 
      } 

      public void columnRemoved(TableColumnModelEvent e) { 
      } 

      public void columnMoved(TableColumnModelEvent e) { 
       //this is called so many times 
       //I don't want this, but something like column moved finished event 
       System.out.println("Moved "+e.getFromIndex()+", "+e.getToIndex()); 
      } 

      public void columnMarginChanged(ChangeEvent e) { 
      } 

      public void columnSelectionChanged(ListSelectionEvent e) { 
      } 
     }); 

Tôi hy vọng nó rõ ràng những gì tôi đang tìm kiếm. Cảm ơn.

+0

bạn Phải biết khi nào người dùng đã xong kéo một cột, hoặc nó sẽ đủ để biết khi nào thứ tự cột đã thực sự thay đổi (nhưng người dùng vẫn có thể kéo nó hơn nữa)? –

+0

Tôi chỉ muốn biết khi nào người dùng đã hoàn thành việc kéo một cột. Làm thế nào về thông báo thay đổi thứ tự cột? Làm thế nào tôi nên thực hiện điều đó? – ashokgelal

+0

http://stackoverflow.com/questions/1543981/is-there-an-event-called-when-a-column-is-moved-in-a-jtable – Ben

Trả lời

14

Đây là những gì tôi đã kết thúc. Tôi biết nó là bẩn, nhưng nó phù hợp cho những gì tôi đang tìm:

boolean dragComplete = false; 
     apTable.getTableHeader().addMouseListener(new MouseAdapter() { 
      @Override 
      public void mouseReleased(MouseEvent e) { 
       if (dragComplete) { 
        System.out.println("Drag completed"); 
       } 
       dragComplete = false; 
      } 
     }); 
     columnModel.addColumnModelListener(new TableColumnModelListener() { 

      public void columnAdded(TableColumnModelEvent e) { 
      } 

      public void columnRemoved(TableColumnModelEvent e) { 
      } 

      public void columnMoved(TableColumnModelEvent e) { 
       dragComplete = true; 
      } 

      public void columnMarginChanged(ChangeEvent e) { 
      } 

      public void columnSelectionChanged(ListSelectionEvent e) { 
      } 
     }); 
+1

+1 bẩn hay không, điều này thực sự hoạt động thực sự tốt cho ứng dụng hiện tại của tôi, mà (như ứng dụng của người khác có thể làm quá) tiết kiệm chiều rộng, trật tự, và sắp xếp thông tin vào một tập tin prefs. Tôi lưu các tập tin mỗi khi con chuột được phát hành trong tiêu đề, và tất cả các lông tơ trong khi kéo và di chuyển và những gì không còn ảnh hưởng đến tiết kiệm này. – Ben

+1

Tôi sẽ đặt tên cho boolean là "dragging" hoặc tương tự, tên bạn chọn là một chút khó hiểu ... :-) Cảm ơn bạn đã đặt câu hỏi này. – PhiLho

+0

Tôi làm như vậy, mặc dù tôi có lớp tiêu đề bảng của riêng mình, nhưng khái niệm này giống nhau và nó hoạt động. – DejanLekic

0

Nếu tôi hiểu bạn một cách chính xác, có thể bạn muốn xem xét người nghe chuột. Có lẽ sự kiện MOUSE_RELEASED?

+0

Tôi nên làm như thế nào? MOUSE_RELEASED về cái gì? bàn? – ashokgelal

+0

Bạn đang nhấp và kéo một cột? Tại một số điểm, hành động đó sẽ kích hoạt các sự kiện chuột thích hợp. Các MouseListener có thể không biết những gì nó là bạn đang kéo chính xác, nhưng bạn làm, và bạn chỉ có thể nghe cho nút được unpressed. – Jon

+0

Tôi nghĩ rằng gợi ý của bạn ngụ ý bổ sung một MouseListener vào JTable. Nhưng với các phương thức trong MouseListener được gọi ngay cả khi cột không được kéo. – sateesh

4

Đây là lớp bên trong tôi sử dụng để xác định khi nào thứ tự cột đã thay đổi. Lưu ý rằng người dùng có thể không buông chuột vào thời điểm này, vì vậy việc kéo có thể tiếp tục.

private class ColumnUpdateListener implements TableColumnModelListener { 

    int lastFrom = 0; 
    int lastTo = 0; 

    private void verifyChange(int from, int to) { 
     if (from != lastFrom || to != lastTo) { 
     lastFrom = from; 
     lastTo = to; 

     /////////////////////////////////////// 
     // Column order has changed! Do something here 
     /////////////////////////////////////// 
     } 
    } 

    public void columnMoved(TableColumnModelEvent e) { 
     verifyChange(e.getFromIndex(), e.getToIndex()); 
    } 

    public void columnAdded(TableColumnModelEvent e) { 
     verifyChange(e.getFromIndex(), e.getToIndex()); 
    } 

    public void columnRemoved(TableColumnModelEvent e) { 
     verifyChange(e.getFromIndex(), e.getToIndex()); 
    } 

    public void columnMarginChanged(ChangeEvent e) {} 
    public void columnSelectionChanged(ListSelectionEvent e) {} 

}

Nó làm việc tốt cho tôi.

+1

Nó tốt hơn hành vi mặc định nhưng vẫn thay đổi thứ tự cột thường xuyên hơn. Tôi chỉ cần quan sát kết thúc kéo vì tôi cần lưu thứ tự của tất cả các cột ngay khi kéo xong (Tôi không muốn gọi phương thức tiết kiệm đắt tiền của mình thường xuyên). Tôi đăng những gì tôi đã làm. Cảm ơn bạn đã viết mã xuống. Có thể hữu ích cho một người nào đó đến cho một chức năng tương tự. – ashokgelal

+0

+1 cho rằng chúng ta không thể thêm một người nghe chuột vào cột, điều này dường như với tôi một cách thông minh để phát hiện rằng kéo cột đã kết thúc. – sateesh

+0

Có thể hiểu được. Tôi đã viết mã trên bởi vì tiết kiệm thứ tự cột để sở thích trên mỗi sự kiện columnMoved() đã ăn lên CPU. Tôi nghĩ rằng TableColumnModelListener đang thiếu. –

2

Đây có thể là một cách tiếp cận tốt hơn:

table.setTableHeader(new JTableHeader(table.getColumnModel()) { 

     @Override 
     public void setDraggedColumn(TableColumn column) { 
     boolean finished = draggedColumn != null && column == null; 
     super.setDraggedColumn(column); 
     if (finished) { 
      onColumnChange(table); // Handle the event here... 
     } 
     } 
    }); 
+0

Ý tưởng hay, vì tiêu đề đã có trình nghe chuột riêng, ngay cả khi JavaDoc nói "Mã ứng dụng sẽ không sử dụng phương thức rõ ràng "... :-) Có thể cần phải được kết hợp với sự kiện columnMoved để lấy giá trị từ và tới. – PhiLho

1

Đây là những gì làm việc cho tôi (cả hai phong trào cột và thay đổi kích thước lề):

tôi mở rộng bàn và ghi đè lên columnMovedcolumnMarginChanged phương pháp theo cách sau:

... trước hết phải thêm s biến ome cho nhà nước giữ

private int lastMovementDistance = 0; 
private boolean bigMove = false; 
private boolean resizeBegan = false; 

...

@Override 
public void columnMarginChanged(ChangeEvent e) { 
    super.columnMarginChanged(e); 
    if (isShowing()){ 
     resizeBegan = true; 
    } 
} 

@Override 
public void columnMoved(TableColumnModelEvent e) { 
    super.columnMoved(e); 

    //this will be set to 0 when the column is dragged 
    //to where it should begin if released  
    lastMovementDistance = Math.abs(getTableHeader().getDraggedDistance()); 


    if (e.getFromIndex() != e.getToIndex()){ 
    //note, this does not guarantee that the columns will be eventually 
    //swapped - the user may move the column back. 
    //but it prevents us from reacting to movements where 
    //the user hasn't even moved the column further then its nearby region. 
    //Works for me, because I don't care if the columns stay the same 
    //I only need the updates to be infrequent and don't want to miss 
    //changes to the column order 
bigMove = true; 
    } 
} 

... sau đó trong constructor của bảng của tôi làm điều này:

public MyTable(){ 

    ... 

getTableHeader().addMouseListener(new MouseAdapter(){ 

    public void mouseReleased(MouseEvent evt) { 
     if (bigMove && lastMovementDistance == 0){ 
     //react! the tables have possibly switched! 
     } 

      else if (resizeBegan){ 
    //react! columns resized 
     } 

     resizeBegan = false; 
     bigMove = false; 
} 
}); 
    ... 
} 

Đó là kinda giống như một hack, Nhưng nó làm việc cho tôi.

-1

Tất cả câu trả lời đều thất bại trong một trường hợp sử dụng: nếu bảng nằm trong bố cục lấp đầy toàn bộ cửa sổ, sau đó thay đổi kích thước cửa sổ sẽ thay đổi kích thước bảng và do đó cột của bảng. Bằng cách xem các sự kiện chuột trên các tiêu đề cột, chúng tôi không nhận được sự kiện khi người dùng thay đổi kích thước cửa sổ.

Tôi đã xem mã nguồn JBC & bạn bè và phương thức columnMarginChanged() luôn được gọi trong hàm phụ ...- được gọi bởi JTable.doLayout().

Sau đó, giải pháp của tôi là để xem các cuộc gọi doLayout() kích hoạt ít nhất một cộtMarginThay đổi().

Thực tế, columnMarginChanged() được gọi cho mỗi cột.

Đây là giải pháp của tôi:

private class ResizableJTable extends JTable { 

    private TableColumnModelListener columnModelListener; 

    private boolean columnsWereResized; 

    @Override 
    public void setColumnModel(TableColumnModel columnModel) { 
     if (getColumnModel() != null) { 
      getColumnModel().removeColumnModelListener(columnModelListener); 
      columnModelListener = null; 
     } 

     if (columnModel != null) { 
      columnModelListener = new TableColumnModelListener() { 

       public void columnSelectionChanged(ListSelectionEvent e) { 
        // Nothing to do 
       } 

       public void columnRemoved(TableColumnModelEvent e) { 
        // Nothing to do 
       } 

       public void columnMoved(TableColumnModelEvent e) { 
        // Nothing to do 
       } 

       public void columnMarginChanged(ChangeEvent e) { 
        columnsWereResized = true; 
       } 

       public void columnAdded(TableColumnModelEvent e) { 
        // Nothing to do 
       } 
      }; 

      columnModel.addColumnModelListener(columnModelListener); 
     } 

     super.setColumnModel(columnModel); 
    } 

    @Override 
    public void doLayout() { 
     columnsWereResized = false; 
     super.doLayout(); 
     if (columnsWereResized) { 
      onColumnsResized(); 
     } 
    } 

    /** 
    * Sub-classes can override this method to 
    * get the columns-were-resized event. 
    * By default this method must be empty, 
    * but here we added debug code. 
    */ 
    protected void onColumnsResized() { 
     int[] columnSizes = getColumnSizes(); 
     String sizes = ""; 
     for (int i : columnSizes) { 
      sizes += i + " "; 
     } 
     System.out.println("COLUMNS RESIZED: [ " + sizes + "]"); 
    } 

    protected int[] getColumnSizes() { 
     TableColumnModel columnModel = getTableHeader().getColumnModel(); 
     int columnCount = columnModel.getColumnCount(); 
     int[] columnSizes = new int[columnCount]; 

     for(int i = 0; i < columnCount; i++) { 
      TableColumn column = columnModel.getColumn(i); 
      columnSizes[i] = column.getWidth(); 
     } 

     return columnSizes; 
    } 
} 
+0

Tôi không chắc chắn những gì bạn đang cố gắng nói, nhưng tôi nghĩ rằng bạn có thể bị nhầm lẫn. Thay đổi kích thước cột không di chuyển cột. Sau khi thay đổi kích thước, chỉ mục cột là như nhau. OP muốn biết một cách hay để biết khi nào sự kiện "Column Moved" được thực hiện. – hfontanez

1

Nice câu trả lời về câu hỏi của riêng bạn ashokgelal. Chỉ cần một chút cải thiện tôi nghĩ. Mã của bạn cũng kích hoạt trên nhấp chuột duy nhất trên tiêu đề. Sử dụng một cờ nữa bạn có thể ngăn chặn trình kích hoạt 'dragComplete' khi cột không thực sự thay đổi. đang Modified:

boolean mDraggingColumn = false; 
    boolean mColumnCHangedIndex = false; 

    tblObjects.getTableHeader().addMouseListener(new MouseAdapter() { 
     @Override 
     public void mouseReleased(MouseEvent e) { 
      if (mDraggingColumn && mColumnCHangedIndex) { 
       System.out.println("Column changed"); 
      } 
      mDraggingColumn = false; 
      mColumnCHangedIndex = false; 
     } 
    }); 
    tblObjects.getColumnModel().addColumnModelListener(new TableColumnModelListener() { 
     @Override 
     public void columnAdded(TableColumnModelEvent e) {} 
     @Override 
     public void columnRemoved(TableColumnModelEvent e) {} 
     @Override 
     public void columnMoved(TableColumnModelEvent e) { 
      mDraggingColumn = true; 
      if (e.getFromIndex() != e.getToIndex()) { 
       mColumnCHangedIndex = true; 
      } 
     } 
     @Override 
     public void columnMarginChanged(ChangeEvent e) {} 
     @Override 
     public void columnSelectionChanged(ListSelectionEvent e) {} 
    }); 
Các vấn đề liên quan