Drag&Drop zwischen 2 Listen

ElJarno

Mitglied
Hi Leute,
hab mal versucht das generelle D&D Konzept zu verstehen und es auf mein Problem anzuwenden. Habe 2 JList zwischen denen allgemeine Objekte per Drag & Drop ausgetauscht werden sollen. Dabei soll in die eine Liste das Objekt kopiert werden und falls erfolgreich dieses Objekt aus der anderen Liste gelöscht werden. Hab mal ein paar Ansätze realisiert, erscheint mir alles aber ziemlich star und undynamisch zu sein, sprich Viele setzen einfach hart ein listmodel und dementsprechend addelement und remove mit in den DropTargetListener:
Code:
		list1.setDropTarget(new DropTarget(list1, new DropTargetAdapter() {
			public void drop(DropTargetDropEvent dtde) {
				try {
					SomeClass someClass = (SomeClass) dtde.getTransferable()
							.getTransferData(someClassFlavor);
					listModel1.removeElement(someClass);
					listModel2.addElement(someClass);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}));
Wollte hingegen um es auch für andere Sachen wie JTable etc. anwenden zu können es dynamischer gestalten und die Componenten aus den Events bekommen. So hier jetzt mal Ansatz:
Code:
...
		this.objectFlavor = new DataFlavor(Object.class, Object.class
				.getSimpleName());

		DragSource dragSource = new DragSource();
		DragGestureRecognizer dgr = dragSource
				.createDefaultDragGestureRecognizer(listVerfuegbareProdukte,
						DnDConstants.ACTION_MOVE,
						new DragGestureObjectListener());
		dgr.getDragSource().addDragSourceListener(
				new DragSourceObjectListener());
		listVerfuegbareProdukte.setDropTarget(new DropTarget(
				listVerfuegbareProdukte, DnDConstants.ACTION_MOVE,
				new DropTargetObjectListener()));

		DragSource dragSource2 = new DragSource();
		DragGestureRecognizer dgr2 = dragSource2
				.createDefaultDragGestureRecognizer(listSelektierteParameter,
						DnDConstants.ACTION_MOVE,
						new DragGestureObjectListener());
		dgr2.getDragSource().addDragSourceListener(
				new DragSourceObjectListener());
		listSelektierteParameter.setDropTarget(new DropTarget(
				listSelektierteParameter, DnDConstants.ACTION_MOVE,
				new DropTargetObjectListener()));
...

	private class DropTargetObjectListener implements DropTargetListener {
		@Override
		public void dragEnter(DropTargetDragEvent dtde) {
		}

		@Override
		public void dragExit(DropTargetEvent dte) {
		}

		@Override
		public void dragOver(DropTargetDragEvent dtde) {
		}

		@Override
		public void drop(DropTargetDropEvent dtde) {
			try {
				Transferable tr = dtde.getTransferable();
				JList tempList = (JList) ((DropTarget) dtde.getSource())
						.getComponent();
				Object obj = null;
				for (DataFlavor flav : tr.getTransferDataFlavors()) {
					obj = tr.getTransferData(flav);
				}
				((DefaultListModel) tempList.getModel()).addElement(obj);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		@Override
		public void dropActionChanged(DropTargetDragEvent dtde) {
		}

	}

	private class DragSourceObjectListener implements DragSourceListener {
		@Override
		public void dragDropEnd(DragSourceDropEvent dsde) {
			boolean drop = dsde.getDropSuccess();
			TransferableObjectClass tr = (TransferableObjectClass) dsde
					.getDragSourceContext().getTransferable();
			JList tempList = (JList) dsde.getDragSourceContext().getComponent();
			Object obj = null;
			for (DataFlavor flav : tr.getTransferDataFlavors()) {
				try {
					obj = tr.getTransferData(flav);
				} catch (UnsupportedFlavorException e) {
					e.printStackTrace();
				}
			}
			((DefaultListModel) tempList.getModel()).removeElement(obj);
		}

		@Override
		public void dragEnter(DragSourceDragEvent dsde) {
		}

		@Override
		public void dragExit(DragSourceEvent dse) {
		}

		@Override
		public void dragOver(DragSourceDragEvent dsde) {
		}

		@Override
		public void dropActionChanged(DragSourceDragEvent dsde) {
		}

	}

	private class DragGestureObjectListener implements DragGestureListener {
		@Override
		public void dragGestureRecognized(DragGestureEvent e) {
			JList tempList = (JList) e.getComponent();
			Object obj = tempList.getSelectedValue();
			TransferableObjectClass transferable = new TransferableObjectClass(
					obj);
			e.startDrag(DragSource.DefaultMoveDrop, transferable);
		}

	}

	private class TransferableObjectClass implements Transferable {
		private Object object;

		public TransferableObjectClass(Object object) {
			this.object = object;
		}

		public Object getTransferData(DataFlavor flavor)
				throws UnsupportedFlavorException {
			if (!flavor.equals(objectFlavor)) {
				throw new UnsupportedFlavorException(flavor);
			}
			return this.object;
		}

		public DataFlavor[] getTransferDataFlavors() {
			return new DataFlavor[] { objectFlavor };
		}

		public boolean isDataFlavorSupported(DataFlavor flavor) {
			return flavor.equals(objectFlavor);
		}
	}

Jetzt funktioniert das ganz schon so ganz oke nur wenn ich den Drag auserhalb also im nicht gültigen Bereich beende wird das Objekt aus der JList trotzdem gelöscht.
1. Was fehlt bei diesem Ansatz noch um dieses Problem zu lösen
2. Wie würde ein genereller Ansatz zur Implementierung von D&D aussehen, bezüglich DragGestureListener, DragSourceListener,DropTargetListener, Transferable und Transferhandler. Mache überschreiben ja den Transferhandler anderer erstellen eigene Dataflavor Transferable u.s.w. Habe halt noch nicht so ganz die Zusammenhänge zwischen den einzelnen Elementen verstanden.

Mit dem Tuturial von Sun konnte ich so nichts anfangen bzw. ist mein Englisch nicht so gut um da mal schnell drüber zu lesen.

Wäre cool wenn mir jemand besonders zu Punkt 2Tips, Links oder eine direkte Erklärung geben kann.

Gruß Jan
 
Zuletzt bearbeitet:
Howdie.

Das Problem ist, dass DnD per Tranferhandler zu erklären recht viel Zeit erfordert. Daher würde ich hier nur bedingt mit ausführlichen Antworten rechnen.
Ich hab mich auch mit dem Sun-Tutorial langsam rangetastet und es ist recht großer Haufen Code geworden. Was ich von vor herein sagen kann: Falls du lediglich DnD-fähige Swing-Komponenten benutzt (JList, JTable, JTree...), brauchst du weder DragGestureListener, -Source- oder -TargetListener. Diese Komponenten erkennen DnD-Gestures selbst und erkennen auch die entsprechenden Tasten-Kombinationen, wenn sie per setDragEnabled() und setDropMode() konfiguriert wurden.

Eine kurze Übersicht über die nötigen Schritte:

  1. Schreib dir eine Transfer-Klasse, welche beim DnD-Vorgang die ex-/importierten Daten enthält. Implementiere hier das Interface Transferable
  2. Leite eine (am besten für jede beteiligte Swing-Komponente eine individuelle) Klasse vom Typ TransferHandler ab und überschreib die Methoden
    - createTransferable(JComponent c) -> erzeugt ein Transferable-Objekt und gibt es für den Export zurück. Diese Methode wird z.B. aufgerufen, wenn du Strg+C drückst oder die entsprechende Maus-Bewegung durchführst.
    - importData(TransferSupport support) -> das TransferSupport-Objekt enthält die importierten Daten in Form eines Transferable-Objekts, die du jetzt auslesen und dem Ziel-Objekt hinzufügen kannst
  3. Füge der Swing-Komponente eine Instanz der TransferHander-Klasse über setTransferHandler() hinzu.

Hier gibts es allerdings echt noch ein paar Sachen zu beachten... Du musst Data-Flavors überprüfen, Legitimität von DnD-Vorgängen, zwischen DnD und CCP unterscheiden, usw.
Ich würde mich an deiner Stelle (vielleicht mit Google-Translator) doch mal an das Tutorial von Sun wagen.

Gruß und viel Erfolg
miffi
 
Zuletzt bearbeitet:
Zurück