Swing JList keine Selektionsänderung bei "dragged-Maus"

Dumdidum

Mitglied
Also prinzipiell habe ich eine JList in der ich mehrere Miniaturbilder habe, die ich dann durch Drag/Drop einer Visualisierung übergebe. Allerdings hatte ich erst immer das Problem, dass hierbei oft komische Exceptions geworfen wurden. Die Lösung war hierbei, das "list.setDragEnabled(true)" heraus zu schmeißen.

Nun habe ich aber ein neues Problem.

Wenn ich ein Element in der Liste markiert habe und bei gedrückter linken Maustaste es ins "Ziel" bewege oder in der Liste bewege kommt es "manchmal" dazu, dass ein anderes Element der Liste (über dem ich mich gerade befinde) selektiert wird.
Prinzipiell ist das ja das Standard Verhalten. Allerdings scheint dies durch hinzufügen der "DragSource" nicht mehr der normal Fall zu sein (was auch gewünscht ist).
Zumindest funktioniert meistens alles wie gewünscht und dann wechselt die Selektierung bei der Bewegung dann doch wieder.

Mein Ziel ist es also, dass ein Element nur bei einem Klick selektiert werden kann und nicht bei Drag Bewegungen.

Java:
JList list = new JList(defaultListModel);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setCellRenderer(new ImageRenderer());

// list.setDragEnabled(true); (wird nicht benutzt)

DragSource ds = new DragSource();
ds.createDefaultDragGestureRecognizer(list, DnDConstants.ACTION_COPY,this);

so in etwa hätte ich mir es gedacht. Wirkt aber nicht:

Java:
		list.addMouseMotionListener(new MouseMotionListener() {
			
			@Override
			public void mouseMoved(MouseEvent e) {
			}
			
			@Override
			public void mouseDragged(MouseEvent e) {
				e.consume();
			}
		});

Hoffe ich hab mein Problem verständlich genug geschildert.

Schonmal Danke =)
 
Ok ich habe jetzt mal ein kleines Beispiel heraus genommen:

Java:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.io.IOException;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;


public class ListTest extends JFrame {

	private static final long serialVersionUID = 1L;

	ListTest() {
		// only makes a Frame
		
		JPanel framePanel = new JPanel();
		framePanel.setLayout(new BoxLayout(framePanel, BoxLayout.Y_AXIS));
		
		Box firstLineBox = Box.createHorizontalBox();
		firstLineBox.add(new OneList());
		firstLineBox.add(new OneList());
		
		Box secondLineBox = Box.createHorizontalBox();
		secondLineBox.add(new OneList());
		secondLineBox.add(new OneList());
				

		framePanel.add(firstLineBox);
		framePanel.add(secondLineBox);

		this.add(framePanel);
		
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setSize(600, 400);
		this.setVisible(true);
	}
	public static void main(String[] args) {
		new ListTest();
	}

}

class OneList extends JPanel implements DragSourceListener,
		DragGestureListener, DropTargetListener {
	private static final long serialVersionUID = 1L;
	JList<String> list;
	DropTarget dropTarget = null;
	DragSource ds;

	OneList() {
		dropTarget = new DropTarget(this, DnDConstants.ACTION_COPY, this);

		this.setLayout(new BorderLayout());
		
		String[] s = new String[100];
		for (int i = 0; i<s.length; i++) {
			s[i] = i+"";
		}

		list = new JList<String>(s);
		list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		list.setCellRenderer(new ImageRenderer());
		// list.setVisibleRowCount(1);
		list.setSelectedIndex(0);
		list.setLayoutOrientation(JList.HORIZONTAL_WRAP);

		this.add(BorderLayout.CENTER, new JScrollPane(list));

		ds = new DragSource();
		ds.createDefaultDragGestureRecognizer(list, DnDConstants.ACTION_COPY,
				this);
		
		// list.setDragEnabled(true);

	}

	@Override
	public void dragEnter(DropTargetDragEvent dtde) {
	}

	@Override
	public void dragOver(DropTargetDragEvent dtde) {
	}

	@Override
	public void dropActionChanged(DropTargetDragEvent dtde) {
	}

	@Override
	public void dragExit(DropTargetEvent dte) {
	}

	@Override
	public void drop(DropTargetDropEvent dtde) {
		try {
			Transferable tr = dtde.getTransferable();
			if (tr != null) {
				if (tr.isDataFlavorSupported(DataFlavor.stringFlavor)) {

					System.out.println("drop: "+tr.getTransferData(DataFlavor.stringFlavor));
					dtde.dropComplete(true);
				} 
			} else {
				dtde.rejectDrop();
			}
		} catch (Throwable t) {
			dtde.rejectDrop();
		}
	}

	@Override
	public void dragGestureRecognized(DragGestureEvent dge) {
		System.out.println("Drag Gesture Recognized!");

		if (list.getModel().getSize() > 0) {
			if (list.getSelectedIndex() != -1) {
				dge.startDrag(DragSource.DefaultCopyDrop, new Transferable() {
					public Object getTransferData(DataFlavor flavor)
							throws UnsupportedFlavorException, IOException {
						if (flavor.equals(DataFlavor.stringFlavor)) {
							return list.getSelectedValue();
						}
						throw new UnsupportedFlavorException(flavor);
					}

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

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

	@Override
	public void dragEnter(DragSourceDragEvent dsde) {
	}

	@Override
	public void dragOver(DragSourceDragEvent dsde) {
	}

	@Override
	public void dropActionChanged(DragSourceDragEvent dsde) {

	}

	@Override
	public void dragExit(DragSourceEvent dse) {

	}

	@Override
	public void dragDropEnd(DragSourceDropEvent dsde) {
	}
}

class ImageRenderer extends DefaultListCellRenderer {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public ImageRenderer() {
	}

	@Override
	public Component getListCellRendererComponent(JList<?> list, Object value,
			int index, boolean isSelected, boolean cellHasFocus) {
		// for default cell renderer behavior
		Component c = super.getListCellRendererComponent(list, value, index,
				isSelected, cellHasFocus);

		((JLabel) c).setText(value.toString());
		((JLabel) c).setToolTipText(value.toString());
		return c;
	}
}

Kleine Info:
Eigentlich werden Bilder bei mir angezeigt, aber ich habe alles zu Strings geändert, dass das Beispiel
ohne weiteren Aufwand zu starten ist.

Wann kommt es zum Problem:
- Selektiere in einer Liste einen Wert und halte die linke Maustaste gedrückt, während der Mauszeiger in der eigenen Liste oder in anderen herum bewegt wird. Dabei kommt es "MANCHMAL" dazu, dass plötzlich ein anderer Wert der Liste selektiert wird.


Eine "Lösung" ist sicher
Java:
 list.setDragEnabled(true);
zu benutzen. Allerdings kommt es dann relativ häufig auch zu einer:
Java:
Exception in thread "AWT-EventQueue-0" java.awt.dnd.InvalidDnDOperationException: Drag and drop in progress
	at sun.awt.dnd.SunDragSourceContextPeer.setDragDropInProgress(SunDragSourceContextPeer.java:356)
	at java.awt.dnd.DragSource.startDrag(DragSource.java:301)

Und hierbei hab ich eben erst in manchen Foren gelesen, dass man das setDragEnabled weg lassen soll.

Gibt es eine Möglichkeit beide ungewollte Verhalten los zu werden?
 
Ich hab jetzt mal ganz einfach aus dem Java Tutorial den ListTranferHandler rauskopiert, deinen Code aufgeräumt und siehe da es funktioniert:

Java:
import java.awt.BorderLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;

import javax.swing.*;

public class ListTest extends JFrame
{
	private static final long serialVersionUID = 1L;
	private ListTransferHandler transferHandler=new ListTransferHandler();
	
	ListTest()
	{
		// only makes a Frame
		
		JPanel framePanel = new JPanel();
		framePanel.setLayout(new BoxLayout(framePanel, BoxLayout.Y_AXIS));
		
		Box firstLineBox = Box.createHorizontalBox();
		firstLineBox.add(createList());
		firstLineBox.add(Box.createHorizontalGlue());
		firstLineBox.add(createList());
		
		Box secondLineBox = Box.createHorizontalBox();
		secondLineBox.add(createList());
		secondLineBox.add(Box.createHorizontalGlue());
		secondLineBox.add(createList());
		
		framePanel.add(firstLineBox);
		framePanel.add(Box.createVerticalGlue());
		framePanel.add(secondLineBox);
		
		this.add(framePanel);
		
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setSize(600, 400);
		this.setVisible(true);
	}
	
	public static void main(String[] args)
	{
		new ListTest();
	}
	
	private JList<String> createList()
	{

		DefaultListModel<String> model=new DefaultListModel<String>();
		for (int i = 0; i < 100; i++)
		{
			model.addElement(String.valueOf(i));
		}
		
		JList<String> list=new JList<String>(model);
		list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		list.setSelectedIndex(0);
		list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
		
		this.add(BorderLayout.CENTER, new JScrollPane(list));
		
		list.setDragEnabled(true);
		list.setDropMode(DropMode.INSERT);
		list.setTransferHandler(transferHandler);
		return list;
	}
	
}

class ListTransferHandler extends TransferHandler
{
	int index;
	public boolean canImport(TransferHandler.TransferSupport info)
	{
		// Check for String flavor
		if (!info.isDataFlavorSupported(DataFlavor.stringFlavor))
		{
			return false;
		}
		return true;
	}
	
	protected Transferable createTransferable(JComponent c)
	{
		JList<String> list = (JList<String>) c;	
		index=list.getSelectedIndex();
		String data=list.getSelectedValue();
		return new StringSelection(data);
	}
	
	/**
	 * We support both copy and move actions.
	 */
	public int getSourceActions(JComponent c)
	{
		return TransferHandler.MOVE;
	}
	
	/**
	 * Perform the actual import. This demo only supports drag and drop.
	 */
	public boolean importData(TransferHandler.TransferSupport info)
	{
		if (!info.isDrop())
		{
			return false;
		}
		
		JList<String> list = (JList<String>) info.getComponent();
		DefaultListModel<String> listModel = (DefaultListModel<String>) list.getModel();
		JList.DropLocation dl = (JList.DropLocation) info.getDropLocation();
		int index = dl.getIndex();
		
		// Get the string that is being dropped.
		Transferable t = info.getTransferable();
		String data;
		try
		{
			data = (String) t.getTransferData(DataFlavor.stringFlavor);
		} catch (Exception e)
		{
			return false;
		}
		
		listModel.add(index++, data);
		return true;
	}
	
	/**
	 * Remove the items moved from the list.
	 */
	protected void exportDone(JComponent c, Transferable data, int action)
	{
		JList<String> source = (JList<String>) c;
		DefaultListModel<String> listModel = (DefaultListModel<String>) source.getModel();
		
		if (action == TransferHandler.MOVE)
		{
				listModel.removeElementAt(index);
		}
	}
}
 
Danke Dir. Durch diese Variante hat es auch bei meinem eigentlichen Code funktioniert.
Das Beispiel oben war letztentlich nur ein Beispiel wo das gleiche Problem auftritt.
 

Zurück
Oben