Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Java drag & drop

102 views
Skip to first unread message

Malcolm Lidierth

unread,
Aug 22, 2007, 11:51:14 AM8/22/07
to
Here are two attempts to implement drop & drag. The second
method is successful in invoking the callback, but access
to hObj and EventData (e,g, through get) then cause
exceptions. Does anyone (are you there Yair) have any ideas?

function droptrial()
f=figure();
j=javacomponent('javax.swing.JComboBox',[],f);
j.setEditable(true);
e=get(j.Editor,'EditorComponent');

% METHOD 1
% This produces an exception and fails:
dnd=e.getDropTarget();
set(dnd, 'DropCallback', @MyCallback);

% METHOD 2
% This works but calls like get(hObj) produce exceptions in
the callback
dnd=java.awt.dnd.DropTarget();
set(dnd, 'DropCallback', @MyCallback);
e.setDropTarget(dnd);
return
end

function MyCallback(hObj, Ev)
get(hObj);
return
end

METHOD1 produces
java.lang.IllegalAccessException: Class
com.mathworks.jmi.bean.MatlabBeanInterface can not access a
member of class javax.swing.TransferHandler$SwingDropTarget
with modifiers "public"
at sun.reflect.Reflection.ensureMemberAccess
(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at
com.mathworks.jmi.bean.MatlabBeanInterface.addCallback
(MatlabBeanInterface.java:691)
at
com.mathworks.jmi.bean.MatlabCallbackInterface.addCallback
(MatlabCallbackInterface.java:128)


METHOD2, when get(hObj) is called from the callback after
making a drop (from a JTree) produces
K>> get(hObj)
Active = on
Class = [ (1 by 1) java.lang.Class array]
Component = [ (1 by 1)
javax.swing.plaf.metal.MetalComboBoxEditor$1 array]
DefaultActions = [3]
DropTargetContext = [ (1 by 1)
java.awt.dnd.DropTargetContext array]
FlavorMap = [ (1 by 1)
java.awt.datatransfer.SystemFlavorMap array]
DropCallback = [ (1 by 1) function_handle array]
DropCallbackDatajava.lang.reflect.InvocationTargetEx
ception
at sun.reflect.NativeMethodAccessorImpl.invoke0
(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke
(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke
(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.mathworks.jmi.bean.ClassInfo.getObjectField
(ClassInfo.java:323)
Caused by: java.awt.dnd.InvalidDnDOperationException: The
operation requested cannot be performed by the DnD system
since it is not in the appropriate state
at java.awt.dnd.DropTargetContext.getTransferable
(Unknown Source)
at java.awt.dnd.DropTargetDropEvent.getTransferable
(Unknown Source)
... 5 more

Yair Altman

unread,
Aug 22, 2007, 5:01:45 PM8/22/07
to
I must admit I'm just as baffled. It appears that
e.setDropTarget() overrides the default call to the drop
target's TransferHandler() method (which is the default text
handler
javax.swing.plaf.basic.BasicTextUI$TextTransferHandler). You
might try to implement your own TransferHandler as explained
here:
http://java.sun.com/docs/books/tutorial/uiswing/dnd/intro.html
. I believe R2007b (Matlab 7.5) uses Java 1.6 and if so,
then you may be interested in the following article:
http://weblogs.java.net/blog/shan_man/archive/2006/02/choosing_the_dr.html

Yair Altman
http://ymasoftware.com

Malcolm Lidierth

unread,
Aug 23, 2007, 9:08:06 AM8/23/07
to
Dear Yair
Many thanks.
The R2007b pre-release produces identical exceptions but
thanks for the links. I think your suggestion is on the
right lines: the problems in the callback seem to arise
through calls to DropTargetDropEvent.getTransferable().
I'll follow the links and try TMW with a service request.
ML

Raphael Austin

unread,
Sep 11, 2007, 10:20:57 AM9/11/07
to
I've posted a drag and drop example, but using Activex.

http://www.mathworks.com/matlabcentral/fileexchange/loadFile
.do?objectId=16312&objectType=file

<a
href="http://www.mathworks.com/matlabcentral/fileexchange/lo
adFile.do?objectId=16312&objectType=file">
http://www.mathworks.com/matlabcentral/fileexchange/loadFile
.do?objectId=16312&objectType=file </a>

Malcolm Lidierth

unread,
Sep 12, 2007, 11:45:49 AM9/12/07
to
Thanks Raphael. Unfortunately, I need a platform-
independent method.

For those interested TMW Support have just sent this to
Development as a bug notice.

I have found a workaround for my specific needs but not a
proper one. Might the drop event have been handled/rejected
in a listener before the callback is activated?

Malcolm Lidierth

unread,
Sep 12, 2007, 12:23:45 PM9/12/07
to
I should have added:

dnd=java.awt.dnd.DropTarget();
dnd=handle(dnd,'callbackProperties')

at least lets you get(hObject) in the callback as long as
you do not call hObject.getTransferable()

Travis Perry

unread,
Nov 18, 2008, 4:54:02 PM11/18/08
to
"Malcolm Lidierth" <ku.c...@htreidil.mloclam> wrote in message <fc93qh$d7j$1...@fred.mathworks.com>...

Did this issue ever get resolved? I am having the same trouble calling getTransferable(). What was the workaround that you used? I need to access the file name and path of the file being dropped. Is there another way to do this?

Malcolm Lidierth

unread,
Nov 19, 2008, 10:35:02 AM11/19/08
to
There is no workaround that I know of. However, I have not tried this out on the most recent MATLAB versions so it is possible that it has been resolved.

Travis Perry

unread,
Nov 20, 2008, 12:31:55 PM11/20/08
to
"Malcolm Lidierth" <ku.c...@htreidil.mloclam> wrote in message <gg1bn6$up$1...@fred.mathworks.com>...

> There is no workaround that I know of. However, I have not tried this out on the most recent MATLAB versions so it is possible that it has been resolved.

Do you know if the source of the problem was ever determined? I don't have the latest version of Matlab, I have the R2007A which I believe is what you were using before. Do you see any other way of getting the file path and name from a file that has been dragged to a figure? I have been stumped on this for quite a while.

Malcolm Lidierth

unread,
Nov 24, 2008, 12:19:02 PM11/24/08
to
Travis
I am afraid not - but its not my area.
Malcolm

Dirk Engel

unread,
Apr 3, 2009, 10:13:01 AM4/3/09
to
"Travis Perry" <travis...@gmail.com> wrote in message <gg46ub$o63$1...@fred.mathworks.com>...

> "Malcolm Lidierth" <ku.c...@htreidil.mloclam> wrote in message <gg1bn6$up$1...@fred.mathworks.com>...
> > There is no workaround that I know of. However, I have not tried this out on the most recent MATLAB versions so it is possible that it has been resolved.
>
> Do you know if the source of the problem was ever determined? I don't have the latest version of Matlab, I have the R2007A which I believe is what you were using before. Do you see any other way of getting the file path and name from a file that has been dragged to a figure? I have been stumped on this for quite a while.

I couldn't pinpoint the exact source of this problem either but do could locate it somewhere within Mathworks DropTargetListener which seems to pass the DropTargetDropEvent (dtde) to the Matlab callback function without accepting the drop before, so dtde.getTransferable() fails.
Since I wasn't able to solve that problem directly, I wrote a new DropTarget class "DropTargetList" which accepts the drop and stores transferable data as java.util.List in a new field. Matlab passes the DropTargetList object to the callback function as first argument:

% initialize new drop target
dnd=javaObjectEDT('DropTargetList')
dnd=handle(dnd,'callbackProperties');


set(dnd, 'DropCallback', @MyCallback);
e.setDropTarget(dnd);

function MyCallback(dropTargetList, dropTargetDropEvent)
data = dropTargetObject.getTransferData();
%...
end


Here's the java code of the DropTargetList class:

import java.awt.dnd.*;
import java.awt.datatransfer.*;
import java.util.List;
import java.io.IOException;

/* Modified DropTarget to be used for drag & drop in Matlab GUIs
*
* Dirk Engel
* Process Systems Engineering
* RWTH Aachen University
*/
public class DropTargetList extends DropTarget {

private Transferable transferable;
private DataFlavor acceptedDataFlavor = DataFlavor.javaFileListFlavor;
private List<?> transferData;
/*********************************************************************/

public synchronized void drop(DropTargetDropEvent dtde) {
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
super.drop(dtde);

transferable = dtde.getTransferable();
try {
transferData = (List<?>)transferable.getTransferData(acceptedDataFlavor);
} catch (UnsupportedFlavorException e) {
return;
} catch (IOException e) {
return;
}
}

public void setAcceptedDataFlavor(DataFlavor flavor) {
acceptedDataFlavor = flavor; }
public DataFlavor getAcceptedDataFlavor() {
return acceptedDataFlavor; }
public Transferable getTransferable() {
return transferable; }
public List<?> getTransferData() {
return transferData; }
}

Note to Yair Altman's suggestion to override the default drop target's TransferHandler(): I tried it and this also works but is much more difficult because one has to use JMI to call Matlab from Java. Also you get an error when calling "figure" from within the callback after compiling the m-file to a standalone application (very strange)

Hope this solves the DND problem once and for all.

Yair Altman

unread,
Apr 4, 2009, 3:22:01 PM4/4/09
to
> I couldn't pinpoint the exact source of this problem either but do could locate it somewhere within Mathworks DropTargetListener which seems to pass the DropTargetDropEvent (dtde) to the Matlab callback function without accepting the drop before, so dtde.getTransferable() fails.
> Since I wasn't able to solve that problem directly, I wrote a new DropTarget class "DropTargetList" which accepts the drop and stores transferable data as java.util.List in a new field. Matlab passes the DropTargetList object to the callback function as first argument: [snip...]

I'm afraid the acceptDrop() hunch is incorrect, since if you call dtde.acceptDrop() in the Matlab callback it still does not prevent an InvalidDnDOperationException being thrown from dtde.getTransferable().

I've tried to implement a Matlab-only approach that uses Java, but which does not require compiling a new Java class. I was successful to a point - perhaps others on this thread will have an idea how to proceed:

The basic idea is to use a list of plot command strings as drag source, and drop its items onto Matlab axes that will plot the requested command. Here's the setup:

% Set-up a figure with draggable list-box and 2 droppable axes
hFig = figure('name','DND example','numbertitle','off');
plotNames = {'surfc(peaks)','contour(peaks)','contourf(peaks)', ...
'surf(membrane)','contour(membrane)','contourf(membrane)'};
jListbox = javax.swing.JList(plotNames);
[hjList,hcList] = javacomponent(jListbox,[10,10,100,200],hFig);
set(hcList,'units','norm','position',[.05,.05,.3,.6]);
hAx1 = axes('position',[.5,.1,.45,.35]);
hAx2 = axes('position',[.5,.55,.45,.35]);
jListbox.setDragEnabled(1);

% Enable drop on the figure axes
dnd = handle(java.awt.dnd.DropTarget(),'callbackProperties');
jFrame = get(hFig,'JavaFrame');
jAxis = jFrame.getAxisComponent;
jAxis.setDropTarget(dnd);
set(dnd,'DropCallback',{@dndCallbackFcn,hFig});
set(dnd,'DragOverCallback',@dndCallbackFcn);

Now the callback. I'm using a persistent transferable to overcome the intermittent behavior of the transferable object - sometime during the drag a valid transferable is available and them I'm grabbing it for reuse during the drop:

% The callback function
function dndCallbackFcn(varargin)
persistent transferable
eventData = varargin{2};
if eventData.isa('java.awt.dnd.DropTargetDropEvent') %nargin>2
hFig = get(0,'PointerWindow'); %varargin{3};
hAxes = overobj('axes');
if ~isempty(hAxes)
try transferable = eventData.getTransferable; catch, end
dataFlavorStr = 'text/plain; class=java.lang.String';
dataFlavor = java.awt.datatransfer.DataFlavor(dataFlavorStr);
dataStr = transferable.getTransferData(dataFlavor);
eventData.acceptDrop(eventData.getDropAction);
axes(hAxes(1));
set(hFig,'pointer','watch');
eval(dataStr);
%obj.getComponent.repaint; % not really necessary
eventData.dropComplete(true);
set(hFig,'pointer','arrow');
else
eventData.rejectDrop();
end
eventData.dropComplete(true);
elseif eventData.isa('java.awt.dnd.DropTargetDragEvent')
try transferable = eventData.getTransferable; catch, end
hAxes = overobj('axes');
if isempty(hAxes)
eventData.rejectDrag;
else
eventData.acceptDrag(eventData.getDropAction);
end
end

This works with 2 problems - Any ideas anyone?
1) after several drag-&-drops the figure stops accepting drags. It's not a source but a target problem, since DND from the list onto the editor still works.
2) the above does not work with a Matlab uicontrol('style','listbox') - setDragEnabled(1) on the underlying com.mathworks.hg.peer.ListboxPeer$UicontrolList is not enough to make the listbox draggable.

> Note to Yair Altman's suggestion to override the default drop target's TransferHandler(): I tried it and this also works but is much more difficult because one has to use JMI to call Matlab from Java. Also you get an error when calling "figure" from within the callback after compiling the m-file to a standalone application (very strange)

I would be grateful if you could post your code for us to learn.

Yair Altman
http://UndocumentedMatlab.com

Yair Altman

unread,
Apr 4, 2009, 4:08:01 PM4/4/09
to
> I've tried to implement a Matlab-only approach that uses Java, but which does not require compiling a new Java class. I was successful to a point - perhaps others on this thread will have an idea how to proceed:

[snip]

> This works with 2 problems - Any ideas anyone?
> 1) after several drag-&-drops the figure stops accepting drags. It's not a source but a target problem, since DND from the list onto the editor still works.
> 2) the above does not work with a Matlab uicontrol('style','listbox') - setDragEnabled(1) on the underlying com.mathworks.hg.peer.ListboxPeer$UicontrolList is not enough to make the listbox draggable.

To clarify, these two problem exist even when using Dirk Engel's Java class. I could not detect any improvement over the Matlab-only approach. Ideas anyone?

Yair Altman
http://UndocumentedMatlab.com

Erik Koopmans

unread,
Jul 27, 2012, 12:00:23 PM7/27/12
to
> This works with 2 problems - Any ideas anyone?
> 1) after several drag-&-drops the figure stops accepting drags. It's not a source but a target problem, since DND from the list onto the editor still works.
> 2) the above does not work with a Matlab uicontrol('style','listbox') - setDragEnabled(1) on the underlying com.mathworks.hg.peer.ListboxPeer$UicontrolList is not enough to make the listbox draggable.

Hello, here's a solution to problem #2:

The underlying JList in Matlab's listbox has an additional property, 'DragSelectionEnabled', which is enabled by default, and prevents drag-and-drop and MouseDraggedCallbacks on the listbox. Setting the property to false resolves the problem.

The following creates a drag-and-drop-enabled listbox (works in Matlab R2010a):

% Create a Matlab UIcontrol listbox
hListbox = uicontrol( 'style', 'listbox', 'string', {'Item 1' 'Item 2'} );

% Get the listbox's underlying Java control
jScrollPane = findjobj( hListbox );
jListbox = jScrollPane.getViewport.getComponent(0);

% Convert the listbox object to a reference handle
jListbox = handle( jListbox, 'CallbackProperties' );

% Configure drag-and-drop on the listbox
set( jListbox, 'DragSelectionEnabled', false, 'DragEnabled', true );


All the best!

Erik Koopmans
0 new messages