2009-04-03 20 views
11

OK, este problema está fuera de mi alcance. Estoy tratando de implementar un widget GUI en Swing que permite que los archivos se coloquen en una JTable, y permite arrastrar las filas de la JTable para volver a ordenarlas. Piense en las listas de reproducción de VLC o en iTunes.JTable - arrastre y suelte

Obtuve archivos del SO (Explorador, Buscador, etc.) trabajando muy bien, pero estoy teniendo un momento imposible con la reorganización de las filas de la tabla, una vez que los archivos están dentro. El problema es que cuando agregue un TransferHandler personalizado a la tabla, al arrastrar desde, la tabla se destruye instantáneamente. Este es un código de ejemplo:

import javax.swing.*; 

public class TableTest 
{ 
    public static void main (String [] argv) 
    { 
     // setup table data 
     String [] columns = new String [] {"Foo", "Bar", "Baz", "Quux"}; 
     String [][] data = new String [][] {{"A", "B", "C", "D"}, 
         {"1", "2", "3", "4"}, 
         {"i", "ii", "iii", "iv"}}; 
     // create table 
     JTable table = new JTable(data, columns); 

     // set up drag and drop 
     table.setDragEnabled(true); 
     table.setDropMode(DropMode.INSERT_ROWS); 
     table.setFillsViewportHeight(true); 
     TransferHandler dnd = new TransferHandler() { 
      // here be code to handle drops, and one would 
      // presume drag exporting, too 
     }; 
     table.setTransferHandler(dnd); 
     JScrollPane scroll = new JScrollPane(table); 

     // create and show window 
     JFrame window = new JFrame(); 
     window.getContentPane().add(scroll); 
     window.pack(); 
     window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     window.setVisible(true); 
    } 
} 

Ejecutar este código como está y verá que no se puede iniciar un lastre para la table.If en comentario la llamada a setTransferHandler() sobre la mesa, arrastrando las obras (es decir, cuando empiezo a arrastrar una fila de la tabla, saco el cursor X'd out circle diciendo que no puedo soltarlo allí). Pero tan pronto como se establece un TransferHandler para la tabla, no puedo arrastrar ninguna fila. El problema tiene que estar en TransferHandler, pero lo solucioné y depuré completamente, y he determinado que el arrastre nunca se inicia una vez que hay un TransferHandler en la mesa. ¿Qué estoy haciendo mal?

+0

Cómo impar. Tengo el mismo problema. Estoy tratando de recordar si he hecho algún trabajo en el que tenía una tabla que admitía tanto arrastrar desde como hacia. – willcodejavaforfood

Respuesta

3

Parece que no está utilizando el TransferHandler correctamente. Intenta leer el tutorial here.

Consulte el TransferHandler doc here. El constructor vacío no parece destinado para el uso fuera de una subclase de TransferHandler.

Y no implementa ninguna de las funcionalidades proporcionadas en el TransferHandler estándar provisto en los componentes Swing. Ver extracto del tutorial DnD here (mi negrita):

Nota: Si instala un TransferHandler personalizado en un componente Swing, se sustituye el soporte por defecto. Por ejemplo, si reemplaza TransferHandler de JTextField con uno que solo maneje colores, deshabilitará su capacidad para admitir la importación y exportación de texto. Si debe reemplazar un TransferHandler predeterminado, por ejemplo, uno que maneje texto, necesitará volver a implementar la capacidad de importar y exportar texto. No es necesario que sea tan extenso como lo que proporciona Swing; podría ser tan simple como admitir el sabor de los datos de StringFlavor, según las necesidades de su aplicación.

5

que tenían el mismo problema, no tiene nada que ver con su implementación personalizada de la TransferHandler. Cuando reemplaza TransferHandler, también necesita obtener el DragSource predeterminado y decirle que reconozca el gesto de arrastre. Es posible que también deba implementar su propio Transferible porque tendrá que pasarlo al método DragGestureEvent.startDrag().

table.setTransferHandler(new MyTransferHandler()); 
    table.setDragEnabled(true); 
    DragSource source = DragSource.getDefaultDragSource(); 
    source.createDefaultDragGestureRecognizer(table, DnDConstants.ACTION_COPY, new DragGestureListener() { 

     @Override 
     public void dragGestureRecognized(DragGestureEvent dge) { 
      //grab the selected files from the table model 
      ArrayList<File> files = new ArrayList<File>(); 
      for (int row : table.getSelectedRows()) { 
       files.add((File) dm.getValueAt(row, 1)); 
      } 

      //FileTransferable is a custom Transferable implementation 
      Transferable transferable = new FileTransferable(files); 

      //and this is the magic right here 
      dge.startDrag(null,transferable); 
     } 
    }); 
+1

funcionó para mí si omitía las dos primeras líneas: 'setTransferHandler' y' setDragEnabled'. De hecho, configurar el arrastre habilitado produjo 'InvalidDnDOperationException: Arrastrar y soltar en progreso' para mí. Además, supongo que 'dm' se refiere a' table.getModel() '. –

+0

funcionó impecable. mismo comentario que el afiche que tengo delante, omita las dos primeras líneas. – user1052080

1

yo no quiero entrar en los detalles prácticos de lo que estaba pasando por lo que sólo los métodos delegado la que no estaba interesado en el viejo TransferHandler.

tree.setDragEnabled(true); 
tree.setDropMode(DropMode.XXXX); 
tree.setTransferHandler(new MyTransferHandler(tree.getTransferHandler()); 

Comience con una configuración estándar, pero pase el antiguo TransferHandler a su Custom TransferHandler.

private class MyTransferHandler extends TransferHandler { 
    private TransferHandler delegate; 

    public MyTransferHandler(TransferHandler delegate) { 
    this.delegate = delegate; 
    } 

    public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) { 
    return delegate.canImport(comp, transferFlavors); 
    } 

    public boolean canImport(TransferSupport support) { 
    return true; 
    } 

    protected Transferable createTransferable(JComponent c) { 
    try { 
     Method method = delegate.getClass().getDeclaredMethod("createTransferable", JComponent.class); 
     method.setAccessible(true); 
     return (Transferable) method.invoke(delegate, c); 
    } catch (Exception e) { 
     return super.createTransferable(c); 
    } 
    } 

    public void exportAsDrag(JComponent comp, InputEvent event, int action) { 
    delegate.exportAsDrag(comp, event, action); 
    } 

    protected void exportDone(JComponent source, Transferable data, int action) { 
    try { 
     Method method = delegate.getClass().getDeclaredMethod("exportDone", JComponent.class, Transferable.class, 
      int.class); 
     method.setAccessible(true); 
     method.invoke(delegate, source, data, action); 
    } catch (Exception e) { 
     super.exportDone(source, data, action); 
    } 
    } 

    public int getSourceActions(JComponent c) { 
    return delegate.getSourceActions(c); 
    } 

    public Icon getVisualRepresentation(Transferable t) { 
    return delegate.getVisualRepresentation(t); 
    } 

    public boolean importData(JComponent comp, Transferable t) { 
    return delegate.importData(comp, t); 
    } 

    public boolean importData(TransferHandler.TransferSupport support) { 
    return delegate.importData(support); 
    } 
} 

Uno de gotcha es que createTransferable (JComponent) y exportDone (JComponent, transferible, int) métodos están protegidos por lo que tiene que hacer la reflexión con el fin de delegar en esos métodos. Cuando no hice esta delegación de reflexión, la estrategia no funcionó. Una vez que hice esta delegación, arrastrar y soltar funcionó como se esperaba sin cambiar el DragSource o tener que escribir un nuevo Transferible.

+0

código de ejemplo descuidado. boolean return type canImport no devuelve nada y void return type exportDone lo hace. –

+0

¿Por qué es esto descuidado? En la pregunta, afirma específicamente que está tratando de agregar un TransferHandler a la mesa para admitir drops. Todo su problema es que cuando lo hace, el soporte de arrastre para la tabla deja de funcionar. Lo que ocurre debajo de las cubiertas es que cuando él proporciona su propio TransferHandler, corta el predeterminado instalado en la mesa. Este es un ejemplo de cómo delegar al TransferHandler original desde la tabla y el secreto está usando el reflejo para implementar createTransferable() y exportDone(). Los otros métodos se pueden sobrescribir o delegar a voluntad. – rancidfishbreath

Cuestiones relacionadas