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
http://ymasoftware.com
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>
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?
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()
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?
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.
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
[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