2010-01-29 10 views
11

¿Cómo debo detectar que la acción de columna movida ha finalizado en JTable? He agregado columnModeListener a mi modelo de columna, pero el problema es que el método columnMoved se invoca cada vez que se mueve una columna (en ciertos píxeles). No quiero este comportamiento Solo quiero detectar cuándo finaliza el arrastre de la columna.Evento de columna movida [finalizada] en 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) { 
      } 
     }); 

Espero que esté claro lo que estoy buscando. Gracias.

+0

Debe saber cuando el usuario ha terminado arrastrando una columna, o sería suficiente para saber cuando el orden de las columnas ha cambiado en realidad (pero el usuario todavía puede arrastrar aún más)? –

+0

Solo quiero saber cuando el usuario ha terminado de arrastrar una columna. ¿Qué hay de notificación de cambio de orden de columna? ¿Cómo debería implementar eso? – ashokgelal

+0

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

Respuesta

14

Esto es lo que terminé haciendo. Sé que es sucio, pero se ajusta a lo que busco:

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 sucia o no, esto realmente funciona muy bien para mi aplicación actual, que (como aplicación de todos los demás, probablemente, también lo hace) ataja el ancho, el orden y ordenar información en un archivo de preferencias. Guardo el archivo cada vez que se suelta el mouse en el encabezado, y toda la pelusa mientras se arrastra y se mueve, y eso ya no afecta este guardado. – Ben

+1

Me gustaría nombrar el booleano "arrastrando" o similar, el nombre elegido es un poco confuso ... :-) Gracias por hacer esta pregunta de todos modos. – PhiLho

+0

Hago lo mismo, aunque tengo mi propia clase de encabezado de tabla, pero el concepto es el mismo, y funciona. – DejanLekic

0

Si te entiendo correctamente, tal vez quieras mirar a los oyentes del mouse. Tal vez el evento MOUSE_RELEASED?

+0

qué debería hacer eso? MOUSE_RELEASED en qué? ¿mesa? – ashokgelal

+0

¿Estás haciendo clic y arrastrando una columna? En algún momento, esa acción activará los eventos de mouse apropiados. Es posible que MouseListener no sepa exactamente qué está arrastrando exactamente, pero lo hace, y puede simplemente escuchar que el botón esté sin presionar. – Jon

+0

Creo que su sugerencia implica la adición de un MouseListener a JTable. Pero con eso los métodos en MouseListener se invocan incluso cuando la columna no se arrastra. – sateesh

4

Aquí hay una clase interna que uso para determinar cuándo ha cambiado el orden de las columnas. Tenga en cuenta que el usuario puede no haber soltado el mouse en este momento, por lo que el arrastre puede continuar.

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

}

Ha funcionado bien para mí.

+1

Es mejor que el comportamiento predeterminado, pero el orden de las columnas cambia con más frecuencia. Solo necesito observar el final del arrastre porque necesito guardar el orden de todas las columnas tan pronto como se complete el arrastre (no quiero llamar a mi caro método de guardado con frecuencia). Estoy publicando lo que terminé haciendo. Gracias por escribir los códigos. Podría ser útil para alguien que viene por una funcionalidad similar. – ashokgelal

+0

+1 dado que no podemos agregar un oyente de mouse a la columna, esto me parece una manera inteligente de detectar que la columna arrastrada terminó. – sateesh

+0

Comprensible. Escribí el código anterior porque guardar el orden de las columnas en las preferencias de cada evento columnMoved() estaba consumiendo la CPU. Creo que falta el TableColumnModelListener. –

2

Esto podría ser un mejor enfoque:

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

buena idea, ya que la cabecera ya tiene sus propios oyentes de ratón, incluso si JavaDoc dice "El código de aplicación no utilizará esta método explícitamente "... :-) Podría ser necesario combinarlo con el evento columnMoved para obtener los valores from y to. – PhiLho

1

Esto es lo que funciona para mí (ambos movimientos de columna y cambia el tamaño de margen):

extiendo la mesa y anular el columnMoved y columnMarginChanged métodos de la siguiente manera:

... agregar primero s ome las variables de estado manteniendo

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

... a continuación, en el constructor de mi mesa hago esto:

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

Es un poco como un truco, Pero funciona para mí.

-1

Todas las respuestas fallan en un caso de uso: si la tabla está en un diseño que llena toda la ventana, el cambio de tamaño de la ventana redimensionará la tabla y, por lo tanto, sus columnas. Al observar los eventos del mouse en los encabezados de las columnas, no recibimos el evento cuando el usuario cambia el tamaño de la ventana.

Miré el código fuente de amigos de JTable &, y siempre se llama al método columnMarginChanged() en una función sub-sub-sub ...- llamada por JTable.doLayout().

Luego, mi solución es mirar las llamadas doLayout() que activan al menos una columnaMarginChanged().

De hecho, se llama a columnMarginChanged() para cada columna.

Aquí está mi solución:

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

No estoy seguro de lo que está tratando de decir, pero creo que podría estar equivocado. Cambiar el tamaño de una columna no mueve la columna. Después de redimensionar, el índice de la columna es el mismo. El OP quería saber una buena forma de saber cuándo se realizó el evento "Column Moved". – hfontanez

1

respuesta agradable en su propia pregunta ashokgelal. Solo un poco de mejora, creo. Su código también se activa con un solo clic en el encabezado. Si usa una bandera más, puede evitar el activador 'dragComplete' cuando la columna realmente no ha cambiado. código de modificación:

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) {} 
    }); 
Cuestiones relacionadas