U e5dâ,ã@sXdZddlZdd„ZGdd„dƒZGdd„dƒZGd d „d ƒZd d „Zed krTeƒdS)aFDrag-and-drop support for Tkinter. This is very preliminary. I currently only support dnd *within* one application, between different windows (or within the same window). I am trying to make this as generic as possible -- not dependent on the use of a particular widget or icon type, etc. I also hope that this will work with Pmw. To enable an object to be dragged, you must create an event binding for it that starts the drag-and-drop process. Typically, you should bind to a callback function that you write. The function should call Tkdnd.dnd_start(source, event), where 'source' is the object to be dragged, and 'event' is the event that invoked the call (the argument to your callback function). Even though this is a class instantiation, the returned instance should not be stored -- it will be kept alive automatically for the duration of the drag-and-drop. When a drag-and-drop is already in process for the Tk interpreter, the call is *ignored*; this normally averts starting multiple simultaneous dnd processes, e.g. because different button callbacks all dnd_start(). The object is *not* necessarily a widget -- it can be any application-specific object that is meaningful to potential drag-and-drop targets. Potential drag-and-drop targets are discovered as follows. Whenever the mouse moves, and at the start and end of a drag-and-drop move, the Tk widget directly under the mouse is inspected. This is the target widget (not to be confused with the target object, yet to be determined). If there is no target widget, there is no dnd target object. If there is a target widget, and it has an attribute dnd_accept, this should be a function (or any callable object). The function is called as dnd_accept(source, event), where 'source' is the object being dragged (the object passed to dnd_start() above), and 'event' is the most recent event object (generally a event; it can also be or ). If the dnd_accept() function returns something other than None, this is the new dnd target object. If dnd_accept() returns None, or if the target widget has no dnd_accept attribute, the target widget's parent is considered as the target widget, and the search for a target object is repeated from there. If necessary, the search is repeated all the way up to the root widget. If none of the target widgets can produce a target object, there is no target object (the target object is None). The target object thus produced, if any, is called the new target object. It is compared with the old target object (or None, if there was no old target widget). There are several cases ('source' is the source object, and 'event' is the most recent event object): - Both the old and new target objects are None. Nothing happens. - The old and new target objects are the same object. Its method dnd_motion(source, event) is called. - The old target object was None, and the new target object is not None. The new target object's method dnd_enter(source, event) is called. - The new target object is None, and the old target object is not None. The old target object's method dnd_leave(source, event) is called. - The old and new target objects differ and neither is None. The old target object's method dnd_leave(source, event), and then the new target object's method dnd_enter(source, event) is called. Once this is done, the new target object replaces the old one, and the Tk mainloop proceeds. The return value of the methods mentioned above is ignored; if they raise an exception, the normal exception handling mechanisms take over. The drag-and-drop processes can end in two ways: a final target object is selected, or no final target object is selected. When a final target object is selected, it will always have been notified of the potential drop by a call to its dnd_enter() method, as described above, and possibly one or more calls to its dnd_motion() method; its dnd_leave() method has not been called since the last call to dnd_enter(). The target is notified of the drop by a call to its method dnd_commit(source, event). If no final target object is selected, and there was an old target object, its dnd_leave(source, event) method is called to complete the dnd sequence. Finally, the source object is notified that the drag-and-drop process is over, by a call to source.dnd_end(target, event), specifying either the selected target object, or None if no target object was selected. The source object can use this to implement the commit action; this is sometimes simpler than to do it in the target's dnd_commit(). The target's dnd_commit() method could then simply be aliased to dnd_leave(). At any time during a dnd sequence, the application can cancel the sequence by calling the cancel() method on the object returned by dnd_start(). This will call dnd_leave() if a target is currently active; it will never call dnd_commit(). éNcCst||ƒ}|jr|SdSdS©N)Ú DndHandlerÚroot)ÚsourceÚeventÚh©rú#/usr/lib64/python3.8/tkinter/dnd.pyÚ dnd_startls r c@sDeZdZdZdd„Zdd„Zdd„Zdd „Zdd d „Zdd d„Z dS)rNcCs°|jdkrdS|j ¡}z |jWdStk rD||_||_YnX||_d|_|j|_}|j|_ }d||f|_ |dp‚d|_ |  |j |j ¡|  d|j¡d|d<dS)NézÚcursorÚúZhand2)ZnumÚwidgetZ_rootÚ_DndHandler__dndÚAttributeErrorrrÚtargetZinitial_buttonÚinitial_widgetÚrelease_patternÚ save_cursorÚbindÚ on_releaseÚ on_motion)ÚselfrrrZbuttonrrrr Ú__init__zs$     zDndHandler.__init__cCs2|j}d|_|r.z|`Wntk r,YnXdSr)rrr©rrrrr Ú__del__ŽszDndHandler.__del__c Cs²|j|j}}|j ||¡}|j}d}|rbz |j}Wntk rHYnX|||ƒ}|rZqb|j}q&|j}||kr‚|r®|  ||¡n,|r˜d|_|  ||¡|r®|  ||¡||_dSr) Úx_rootÚy_rootrZwinfo_containingrÚ dnd_acceptrZmasterrÚ dnd_motionÚ dnd_leaveÚ dnd_enter) rrÚxÚyZ target_widgetrÚ new_targetÚattrZ old_targetrrr r—s.    zDndHandler.on_motioncCs| |d¡dS)Né©Úfinish©rrrrr r²szDndHandler.on_releasecCs| |d¡dS)Nrr(r*rrr ÚcancelµszDndHandler.cancelrc Cs’|j}|j}|j}|j}zf|`|j |j¡|j d¡|j|d<d|_|_|_|_|r||rp|  ||¡n |  ||¡W5| ||¡XdS)Nrr ) rrrrÚdnd_endrZunbindrrÚ dnd_commitr!)rrZcommitrrrrrrr r)¸s  zDndHandler.finish)N)r) Ú__name__Ú __module__Ú __qualname__rrrrrr+r)rrrr rvs  rc@sNeZdZdd„Zddd„Zdd„Zdd „Zd d „Zd d „Zdd„Z dd„Z dS)ÚIconcCs||_d|_|_|_dSr)ÚnameÚcanvasÚlabelÚid)rr2rrr rÑsz Icon.__init__é cCs€||jkr |j |j||¡dS|jr.| ¡|s6dStj||jddd}|j|||dd}||_||_||_|  d|j ¡dS)NéZraised)ÚtextZ borderwidthZreliefZnw)ZwindowZanchorz ) r3Úcoordsr5ÚdetachÚtkinterZLabelr2Z create_windowr4rÚpress)rr3r#r$r4r5rrr ÚattachÕs   ÿz Icon.attachcCsB|j}|sdS|j}|j}d|_|_|_| |¡| ¡dSr)r3r5r4ÚdeleteZdestroy)rr3r5r4rrr r:ås z Icon.detachcCs4t||ƒr0|j|_|j|_|j |j¡\|_|_ dSr) r r#Úx_offr$Úy_offr3r9r5Úx_origÚy_origr*rrr r<ïs z Icon.presscCs(| |j|¡\}}|j |j||¡dSr)Úwherer3r9r5)rrr#r$rrr Úmove÷sz Icon.movecCs|j |j|j|j¡dSr)r3r9r5rArB)rrrr Úputbackûsz Icon.putbackcCs8| ¡}| ¡}|j|}|j|}||j||jfSr)Z winfo_rootxZ winfo_rootyrrr?r@)rr3rZx_orgZy_orgr#r$rrr rCþs   z Icon.wherecCsdSrr)rrrrrr r,sz Icon.dnd_endN)r6r6) r.r/r0rr=r:r<rDrErCr,rrrr r1Ïs   r1c@s<eZdZdd„Zdd„Zdd„Zdd„Zd d „Zd d „Zd S)ÚTestercCs>t |¡|_tj|jddd|_|jjddd|j|j_dS)Néd)ÚwidthZheightZbothr')ZfillÚexpand)r;ZToplevelÚtopZCanvasr3Úpackrrrrr rs zTester.__init__cCs|Srr©rrrrrr rszTester.dnd_acceptc Csp|j ¡| |j|¡\}}|j |j¡\}}}}||||} } |j |||| || ¡|_| ||¡dSr)r3Ú focus_setrCÚbboxr5Zcreate_rectangleÚdndidr ) rrrr#r$Úx1Úy1Úx2Úy2ZdxZdyrrr r"s  zTester.dnd_enterc CsF| |j|¡\}}|j |j¡\}}}}|j |j||||¡dSr)rCr3rNrOrD) rrrr#r$rPrQrRrSrrr r szTester.dnd_motioncCs"|j ¡|j |j¡d|_dSr)rJrMr3r>rOrLrrr r!$s zTester.dnd_leavecCs2| ||¡| |j|¡\}}| |j||¡dSr)r!rCr3r=)rrrr#r$rrr r-)s zTester.dnd_commitN) r.r/r0rrr"r r!r-rrrr rF s rFcCsªt ¡}| d¡tj|jdd ¡t|ƒ}|j d¡t|ƒ}|j d¡t|ƒ}|j d¡tdƒ}tdƒ}td ƒ}|  |j ¡|  |j ¡|  |j ¡|  ¡dS) Nz+1+1ZQuit)Zcommandr8z+1+60z+120+60z+240+60ZICON1ZICON2ZICON3) r;ZTkZgeometryZButtonÚquitrKrFrJr1r=r3Zmainloop)rÚt1Út2Zt3Zi1Zi2Zi3rrr Útest/s        rWÚ__main__)Ú__doc__r;r rr1rFrWr.rrrr Úsf Y=#