Drag and drop from tree view

Someone have a example to do a drag and drop a item from tree view to power table? I need to do the same of Tag Browse Tree

My solution
The in source component you must create the following function.

def addDrag(self):
    """
	Arguments:
		self: A reference to the component instance this method is invoked on. This argument
		  is automatic and should not be specified when invoking this method.
	"""
	from java.awt.dnd import DragSource,DragGestureListener
	from java.awt.dnd import DragSourceListener 
	from java.awt.dnd import DnDConstants
	from java.awt.datatransfer import Transferable
	from java.awt.datatransfer import StringSelection
		
		
	class MyDragGestureListener(DragGestureListener):
		def  __init__(self,table):
			DragGestureListener.__init__(self)
			
		def dragGestureRecognized(self,DragGestureEvent): 
		 	transferable = StringSelection("");
			myDragDrop.startDrag(DragGestureEvent, DragSource.DefaultCopyDrop, transferable, myDragSourceListener)
	
	class MyDragSourceListener(DragSourceListener):
		def __init__(self,table):
				DragSourceListener.__init__(self)
		
	class MyDragDrop(DragSource): 
		def __init__(self,table):
			DragSource.__init__(self)
			self.table = table
			
	myDragGestureListener = MyDragGestureListener(self)
	myDragSourceListener = MyDragSourceListener(self)
	myDragDrop =  MyDragDrop(self)
	myDragDrop.createDefaultDragGestureRecognizer(self,DnDConstants.ACTION_COPY_OR_MOVE, myDragGestureListener)
	

If your component have a extension function “initialize” put there “event.source.addDrag()”. but it’s not present you can put in the eventHandrles MousePressed.

In the destination component you have write this code:

def addListener(self):
	"""
	Arguments:
		self: A reference to the component instance this method is invoked on. This argument
		  is automatic and should not be specified when invoking this method.
	"""
	from java.awt.dnd import DropTargetListener, DropTarget
	from com.inductiveautomation.factorypmi.application.components.chart.easychart import ClientNodeListTransferable

	class MyDragDropListener(DropTargetListener):
		def __init__(self, table):
			DropTargetListener.__init__(self)
			self.table = table
			
		def drop(self, e):
			e.acceptDrop(e.getDropAction())			
			print "dropped"

	
	myDragDropListener = MyDragDropListener(self)
	DropTarget(self, myDragDropListener)

In function drop you put the code what do with the information arrive from dop.
If your component have a extension function “initialize” put there “event.source.addListener()”. but it’s not present you can put in the eventHandrles MouseEntered.

this is the solution do for my request

I feel like some basic details are missing from this solution. What else does one need to do to get this to work for, say dragging a selected node string from a tree view to a text field?

In the function “drop”, in your case in the text field, you must write what you want to do with the data you receive.
For example: if you want to take the property “path” from the node you should say:

self.text= [the property path]

I’m sorry I don’t put a working code but I’m not with my computer at hand.
Tomorrow I will try to write a clearer example.

Hi,
i am tried using your code drag from tree view to list

used the script in tree view mouse pressed

#def addDrag(self):	

from java.awt.dnd import DragSource,DragGestureListener,DragSourceAdapter
from java.awt.dnd import DragSourceListener 
from java.awt.dnd import DnDConstants
from java.awt.datatransfer import Transferable
from java.awt.datatransfer import StringSelection

selectedPath = event.source.parent.getComponent('List')
class MyDragGestureListener(DragGestureListener):
	def  __init__(self,selectedPath):
		DragGestureListener.__init__(self)
		
	def dragGestureRecognized(self,DragGestureEvent): 
		transferable = StringSelection("");
		myDragDrop.startDrag(DragGestureEvent, DragSource.DefaultCopyDrop, transferable, myDragSourceListener)

class MyDragSourceListener(DragSourceListener):
	def __init__(self,selectedPath):
			DragSourceListener.__init__(self)
	
class MyDragDrop(DragSource): 
	def __init__(self,selectedPath):
		DragSource.__init__(self)
		self.selectedPath = selectedPath
		
myDragGestureListener = MyDragGestureListener(event.source)
myDragSourceListener = MyDragSourceListener(event.source)
myDragDrop =  MyDragDrop(event.source)
myDragDrop.createDefaultDragGestureRecognizer(event.source,DnDConstants.ACTION_COPY_OR_MOVE, myDragGestureListener)

But i am getting this error

Exception in thread "AWT-EventQueue-0" java.awt.dnd.InvalidDnDOperationException: Drag and drop in progress
	at java.desktop/sun.awt.dnd.SunDragSourceContextPeer.setDragDropInProgress(Unknown Source)
	at java.desktop/java.awt.dnd.DragSource.startDrag(Unknown Source)
	at java.desktop/java.awt.dnd.DragSource.startDrag(Unknown Source)
	at java.base/jdk.internal.reflect.GeneratedMethodAccessor215.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:190)
	at org.python.core.PyObject.__call__(PyObject.java:422)
	at org.python.core.PyMethod.__call__(PyMethod.java:187)
	at org.python.pycode._pyx95.dragGestureRecognized$3(<event:mousePressed>:16)
	at org.python.pycode._pyx95.call_function(<event:mousePressed>)
	at org.python.core.PyTableCode.call(PyTableCode.java:173)
	at org.python.core.PyBaseCode.call(PyBaseCode.java:306)
	at org.python.core.PyBaseCode.call(PyBaseCode.java:197)
	at org.python.core.PyFunction.__call__(PyFunction.java:485)
	at org.python.core.PyMethod.instancemethod___call__(PyMethod.java:237)
	at org.python.core.PyMethod.__call__(PyMethod.java:228)
	at org.python.core.PyMethod.__call__(PyMethod.java:218)
	at org.python.core.PyMethod.__call__(PyMethod.java:213)
	at org.python.core.PyObject._jcallexc(PyObject.java:3565)
	at org.python.core.PyObject._jcall(PyObject.java:3598)
	at org.python.proxies.__builtin__$MyDragGestureListener$31.dragGestureRecognized(Unknown Source)
	at java.desktop/java.awt.dnd.DragGestureRecognizer.fireDragGestureRecognized(Unknown Source)
	at java.desktop/sun.awt.windows.WMouseDragGestureRecognizer.mouseDragged(Unknown Source)
	at com.inductiveautomation.factorypmi.application.components.util.EventDelegateDispatcher$MouseEventDispatcher.mouseDragged(EventDelegateDispatcher.java:145)
	at java.desktop/java.awt.AWTEventMulticaster.mouseDragged(Unknown Source)
	at java.desktop/java.awt.AWTEventMulticaster.mouseDragged(Unknown Source)
	at java.desktop/java.awt.Component.processMouseMotionEvent(Unknown Source)
	at java.desktop/javax.swing.JComponent.processMouseMotionEvent(Unknown Source)
	at java.desktop/java.awt.Component.processEvent(Unknown Source)
	at java.desktop/java.awt.Container.processEvent(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
	at java.base/java.security.AccessController.doPrivileged(Native Method)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
	at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "AWT-EventQueue-0" NotImplementedError: 'MyDragSourceListener' object does not implement abstract method 'dragEnter' from 'java.awt.dnd.DragSourceListener'

can you please let me know. which i need to correct in my script

@prasath.t
I experimented with this, and I found that dragging and dropping to a list was simple to accomplish without having to add listeners to components. Simply add the following script to your Tree View's Mouse Released event handler:

e = event
listComponent = event.source.parent.getComponent('List')
eX = e.x + event.source.x
eY = e.y + event.source.y
x1 = listComponent.x
y1 = listComponent.y
x2 = listComponent.x + listComponent.width
y2 = listComponent.y + listComponent.height
if eX > x1 and eX < x2 and eY > y1 and eY < y2:
	listData = listComponent.data
	if listData.getColumnCount() != 1:
		header = ["Items"]
		rows = []
		listData = system.dataset.toDataSet(header, rows)
	selectedPath = event.source.selectedPath
	data = event.source.data
	pathNotFound = True
	for row in range(data.getRowCount()):
		if selectedPath in data.getValueAt(row, "path"):
			listData = system.dataset.addRow(listData,[data.getValueAt(row, "path") + "/" + data.getValueAt(row, "text")])
			pathNotFound = False
	if pathNotFound:
		listData = system.dataset.addRow(listData,[selectedPath])
	event.source.parent.getComponent('List').data = listData

When a mouse is pressed within the Tree View and subsequently released somewhere else, this code determines if the release point is over the list component by relative mouse location. If the mouse is within the list component at the moment of release, the selected path with all subpaths are added to the list component's dataset. Obviously, if your List component is not named "List" or if the List component is not in the same container as the Tree View, then you will have to correct those lines of code, and it is possible that you will have to delete and recreate the Tree View to remove the listeners you have added, but other than that, this example should be simple to modify for your usage case. Here is a video of the result:

1 Like

Great Its working Thanks

But i have 2question
how to add multiple tags to list same time ( now we able to drag and drop only one tag at a time)

By selecting 2 tags and drag and drop i mean

second question
when we drag to list component

i want mouse to look like this
image

is it possible to do?

At this time, I'm not sure how to enable multiline selection on a Tree View.

It is possible to create a custom cursor. Here are two resources that I would look at for that purpose:

To simply change the cursor to any of the standard options, add this code to your Tree View's mousePressed event handler to initially alter the cursor:

from java.awt import Cursor
event.source.setCursorCode(Cursor.HAND_CURSOR)
event.source.parent.setCursorCode(Cursor.HAND_CURSOR)

and also add this code to your mouseReleased event handler to change the cursor back once the drag is finished:

from java.awt import Cursor
event.source.setCursorCode(Cursor.DEFAULT_CURSOR)
event.source.parent.setCursorCode(Cursor.DEFAULT_CURSOR)
1 Like

Combining the two cursor methods, I believe this code produces a good looking result from the mousePressed event handler:

from java.awt import Toolkit, Point, Cursor
from com.inductiveautomation.ignition.client.images import ImageLoader
tk = Toolkit.getDefaultToolkit()
img = ImageLoader.getInstance().loadImage("Builtin/icons/16/copy.png") 
c = tk.createCustomCursor(img, Point(event.source.parent.getX(), event.source.parent.getY()), "img")
event.source.setCursorCode(Cursor.HAND_CURSOR)
event.source.parent.setCursor(c)

While the cursor is pressed inside the Tree View, you get a hand cursor, but as soon as the mouse is dragged out of the Tree View, the cursor changes to copy mode:
image

The mouseReleased code to change the cursor back remains the same:

from java.awt import Cursor
event.source.setCursorCode(Cursor.DEFAULT_CURSOR)
event.source.parent.setCursorCode(Cursor.DEFAULT_CURSOR)
1 Like

one concern i have the list in a template. so when use your script whenever i click any folder its adding to list component and drag and drop also working

i need to stop mouse click data not be transfered to list

my script

e = event
listComponent = system.gui.getWindow("Data_Superstore/DS_AddMyFav").rootContainer.getComponent('Group 5').getComponent("List")
eX = e.x + event.source.x
eY = e.y + event.source.y
x1 = listComponent.x
y1 = listComponent.y
x2 = listComponent.x + listComponent.width
y2 = listComponent.y + listComponent.height
if eX > x1 and eX < x2 and eY > y1 and eY < y2:
	listData = listComponent.data
	if listData.getColumnCount() != 1:
		header = ["Items"]
		rows = []
		listData = system.dataset.toDataSet(header, rows)
	selectedPath = event.source.selectedPath
	data = event.source.data
	pathNotFound = True
	for row in range(data.getRowCount()):
		if selectedPath in data.getValueAt(row, "path"):
			listData = system.dataset.addRow(listData,[data.getValueAt(row, "path") + "/" + data.getValueAt(row, "text")])
			pathNotFound = False
	if pathNotFound:
		listData = system.dataset.addRow(listData,[selectedPath])
	system.gui.getWindow("Data_Superstore/DS_AddMyFav").rootContainer.getComponent('Group 5').getComponent("List").data = listData

system.gui.getWindow("Data_Superstore/DS_AddMyFav").rootContainer.getComponent('Group 5').getComponent("List").data

this is how i am calling the list

My apologies, but I'm not sure I understand the question. Could you rephrase it?

can you please check the video.. whenever i click the tree view folder. Its adding the folder to list

this is because i am having the list component in template and i am using the list template in the window

this issue is happening

we need to do any change in script? because we using the list in a template?

see in window i am using tree view as template one

image

image

The script should be on the tree view itself in the Tree View's mouseReleased event handler

yes its there only. mosule released i have the script..... that's different script.

Paste this at the beginning of your mouseReleased script and see what it prints in the console. Perhaps it will shed some light on what's going wrong:

Code:
e = event
listComponent = system.gui.getWindow("Data_Superstore/DS_AddMyFav").rootContainer.getComponent('Group 5').getComponent("List")
eX = e.x + event.source.x
eY = e.y + event.source.y
x1 = listComponent.x
y1 = listComponent.y
x2 = listComponent.x + listComponent.width
y2 = listComponent.y + listComponent.height
	print "eX: "+ str(eX)
	print "eY: "+ str(eY)
	print "x1: "+ str(x1)
	print "y1: "+ str(y1)
	print "x2: "+ str(x2)
	print "y2: "+ str(y2)
if eX > x1 and eX < x2 and eY > y1 and eY < y2:
	print "In Bounds"
else:
	print "Out of Bounds"
'''

when i click the folder i am getting

image

I'm curious about these as well:

print "event X: "+ str(event.source.x)
print "event Y: "+ str(event.source.y)

image

Interesting. According to the printout, the two components are overlapping. When you select each component and press Ctrl+P does the popup confirm this?

noo they are different
tree biew resolition