jTable drag & drop einzelner Zeilen

Lirave

Aktives Mitglied
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)
at javax.swing.TransferHandler$SwingDropTarget.drop(Unknown Source)
at sun.awt.dnd.SunDropTargetContextPeer.processDropMessage(Unknown Source)
at sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher.dispatchDropEvent(Unknown Source)
at sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher.dispatchEvent(Unknown Source)
at sun.awt.dnd.SunDropTargetEvent.dispatch(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processDropTargetEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

Java:
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);
	}
}

Java:
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
Java:
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
 
Zuletzt bearbeitet von einem Moderator:
Wie die Exception schon sagt (aber danke dass du sie gepostet hast!) ist das Problem der Cast in Zeile 58:
Java:
        ((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
Code:
getModel()
etwas zurückgeben, dass Reorderable implementiert und in diesem Etwas musst du die Methode
Code:
reorder()
derart programmieren, dass sie dein Tabellenmodell entsprechend ändert.
 
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
 
In der Zeile
Java:
((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
Code:
getModel()
aufgerufen. Die liefert das Modell der Tabelle zurück. Das ist in
Code:
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.
 
Das heißt also, ich muss mir ein eigenes TableModel erstellen, dass das DefaultTableModel implementiert und die Funktion Reorderable. Richtig ?
 

Zurück
Oben