# jTable drag & drop einzelner Zeilen



## Lirave (15. Mrz 2012)

Hallo,

wie im Titel beschrieben, würde ich gerne für meine beiden Tabelle drag&drop einzellner Zeilen aktivieren.
Ich habe gegoogelt und dabei eine Lösung gefunden (die ich nicht verstehe).
Eclipse hat sie ersteinmal angenommen, beim Versuch eine Zeile zu verschieben erhalte ich dann folgende Fehlermeldung:



> java.lang.ClassCastException: medikit.view.Table$1 cannot be cast to medikit.view.Table$Reorderable
> at medikit.view.TableRowTransferHandler.importData(TableRowTransferHandler.java:58)
> at javax.swing.TransferHandler$DropHandler.drop(Unknown Source)
> at java.awt.dnd.DropTarget.drop(Unknown Source)
> ...




```
package medikit.view;

import java.util.Arrays;
import java.util.Vector;

import javax.swing.DropMode;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;





public class Table {	

	private JTable table;
	private DefaultTableModel model;
	
	
	public Table(Vector<?> content,Vector<?> headercont,int[] isNotEditAble,int[][] prefMinMaxWidth, Class<?>[] classtype) {
		table = new JTable();
		initTable(content,headercont,isNotEditAble,prefMinMaxWidth,classtype);
	}	
	
	
	@SuppressWarnings("serial")
	private void initTable(Vector<?> content , Vector<?> headercont,final int[] isNotEditAble,int[][] prefMinMaxWidth,final Class<?>[] classtype) {
		table.setModel(model = new DefaultTableModel(content,headercont) {			
			
			public boolean isCellEditable(int row, int column) {
				Arrays.sort(isNotEditAble);
				if (Arrays.binarySearch(isNotEditAble, column) > -1)
					return false;
				return true;
				}
			
			public Class<?> getColumnClass(int column)	{
				return classtype[column];
				}
			});
		
		for (int i=0; i<prefMinMaxWidth.length; i++) {
			table.getColumnModel().getColumn(i).setPreferredWidth(prefMinMaxWidth[i][0]);
			table.getColumnModel().getColumn(i).setMinWidth(prefMinMaxWidth[i][1]);
			table.getColumnModel().getColumn(i).setMaxWidth(prefMinMaxWidth[i][2]);
		}		
		table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		
		[COLOR="Blue"]table.setDragEnabled(true);
		table.setDropMode(DropMode.INSERT_ROWS);
		table.setTransferHandler(new TableRowTransferHandler(table));[/COLOR]
		
		JTableHeader header = table.getTableHeader();
	    ((DefaultTableCellRenderer)header.getDefaultRenderer()).setHorizontalAlignment(JLabel.CENTER);    
	    header.setReorderingAllowed(false);	    
	        
	}
	
	public JTable getTable() {
		return table;		
	}
	public DefaultTableModel getModel() {
		return model;		
	}
	
	public interface Reorderable {
		public void reorder(int fromIndex, int toIndex);
	}
}
```


```
package medikit.view;

import java.awt.Cursor;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DragSource;

import javax.activation.ActivationDataFlavor;
import javax.activation.DataHandler;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.TransferHandler;

import medikit.view.Table.Reorderable;

/**
 * Handles drag & drop row reordering
 */
@SuppressWarnings("serial")
public class TableRowTransferHandler extends TransferHandler {
   private final DataFlavor localObjectFlavor = new ActivationDataFlavor(Integer.class, DataFlavor.javaJVMLocalObjectMimeType, "Integer Row Index");
   private JTable           table             = null;

   public TableRowTransferHandler(JTable table) {
      this.table = table;
   }

   @Override
   protected Transferable createTransferable(JComponent c) {
      assert (c == table);
      return new DataHandler(new Integer(table.getSelectedRow()), localObjectFlavor.getMimeType());
   }

   @Override
   public boolean canImport(TransferHandler.TransferSupport info) {
      boolean b = info.getComponent() == table && info.isDrop() && info.isDataFlavorSupported(localObjectFlavor);
      table.setCursor(b ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop);
      return b;
   }

   @Override
   public int getSourceActions(JComponent c) {
      return TransferHandler.COPY_OR_MOVE;
   }

   @Override
   public boolean importData(TransferHandler.TransferSupport info) {
      JTable target = (JTable) info.getComponent();
      JTable.DropLocation dl = (JTable.DropLocation) info.getDropLocation();
      int index = dl.getRow();
      int max = table.getModel().getRowCount();
      if (index < 0 || index > max)
         index = max;
      target.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
      try {
         Integer rowFrom = (Integer) info.getTransferable().getTransferData(localObjectFlavor);
         if (rowFrom != -1 && rowFrom != index) {
            ((Reorderable)table.getModel()).reorder(rowFrom, index);
            if (index > rowFrom)
               index--;
            target.getSelectionModel().addSelectionInterval(index, index);
            return true;
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
      return false;
   }

   @Override
   protected void exportDone(JComponent c, Transferable t, int act) {
      if (act == TransferHandler.MOVE) {
         table.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
      }
   }

}
```


Eine Tabelle initialisiere ich z.B. mittels

```
vLager = new Vector<Object> ( Arrays.asList( null, null,null, null, null, null, null, null, null,null, null, null, null, null, null, null,null, null, null, null, null, null, null, null));
tableLager = new Table(vLager,
         new Vector<String> ( Arrays.asList("Medikament", "Wirkstoff", "Dosis", "Anz./Packung", "ges. Stückzahl", "verbraucht bis")),
         new int[] {5},
         new int[][] {{120,80,500},{110,58,500},{58,43,500},{85,85,500},{92,92,500},{90,90,500}},
         new Class[] {String.class,String.class,String.class,Integer.class,Double.class,String.class}
		);
```

Mit freundlichen Grüßen
Lirave


----------



## KrokoDiehl (15. Mrz 2012)

Wie die Exception schon sagt (aber danke dass du sie gepostet hast!) ist das Problem der Cast in Zeile 58:

```
((Reorderable)table.getModel()).reorder(rowFrom, index);
```

Dein Interface _Reorderable_ wird nicht von _Table_ implementiert, bzw. nicht vom Tabellenmodell. Die Idee deiner Quelle ist nämlich folgende:

- D&D zu erlauben heißt dass man an beliebiger Stelle in der Tabelle, respektive im Tabellenmodell, Daten einfügen kann.
- Bei diesem Einfügen muss das Tabellenmodell re-organisiert werden, d.h. es müssen z.B. alle Zeilen nach der neu eingefügten nach hinten verschoben werden.
- Das Re-organisieren wird in dem genannten Interface abstrahiert. Es muss also (von dir) implementiert werden.

Ok, um ehrlich zu sein ist dein direktes Problem natürlich dass du nicht verstehst, was hier geschieht   Daher ist es natürlich ratsam mit Tabellen und Tabellenmodellen zu beginnen denn letztlich müssen die Daten entsprechend im Modell eingefügt/geändert werden, die Tabelle (JTable) dient nur zur Anzeige. Drag&Drop empfinde ich auch schon ein komplexeres Thema...

Die Lösung müsste wie folgt aussehen: Deine Klasse _Table_ muss in ihrer Methode 
	
	
	
	





```
getModel()
```
 etwas zurückgeben, dass _Reorderable_ implementiert und in diesem Etwas musst du die Methode 
	
	
	
	





```
reorder()
```
 derart programmieren, dass sie dein Tabellenmodell entsprechend ändert.


----------



## Lirave (15. Mrz 2012)

Hallo,

ich komme nicht darauf, wo ich jetzt in meiner Datei Table.java nun das Reorderable Interface implementieren kann. Was ich da drin machen muss ist mir glaube ich klar.

Wäre nett wenn Ihr die Stelle in dem Quelltext oben markieren könntet.

Danke


----------



## KrokoDiehl (16. Mrz 2012)

In der Zeile

```
((Reorderable)table.getModel()).reorder(rowFrom, index);
```
wird folgendes gemacht:

Am Objekt table - das ist die JTable die dem Transferhandler im Konstrutkor übergeben wird - wird die Methode 
	
	
	
	





```
getModel()
```
 aufgerufen. Die liefert das Modell der Tabelle zurück. Das ist in 
	
	
	
	





```
Table.initTable()
```
 eine interne Klasse DefaultTableModel.
In der o.g. Zeile wird dieses DefaultTableModel aber zum Reorderable gecastet und das geht nicht, weil es das nicht implementiert.


----------



## Lirave (16. Mrz 2012)

Das heißt also, ich muss mir ein eigenes TableModel erstellen, dass das DefaultTableModel implementiert und die Funktion Reorderable. Richtig ?


----------

