Scheduled Maintenance: We are aware of an issue with Google, AOL, and Yahoo services as email providers which are blocking new registrations. We are trying to fix the issue and we have several internal and external support tickets in process to resolve the issue. Please see: viewtopic.php?t=158230

 

 

 

Need help with tkdnd package on debian linux

Programming languages, Coding, Executables, Package Creation, and Scripting.
Post Reply
Message
Author
allankiipli
Posts: 4
Joined: 2016-01-07 12:00

Need help with tkdnd package on debian linux

#1 Post by allankiipli »

I create a cross platform application and it uses tkdnd to do drag and drop between operating system windows and tkinter widgets.
On windows it looks like
if platform == "win32":
os.environ['TKDND_LIBRARY'] = "C:\Python27\tcl\tkdnd2.8"
On mac the library is found and it works without direction.

But i cannot get it work on debian linux with Cinnamon desktop.
Installed tkdnd with Synaptic Package manager and it went into /usr/lib/tkdnd2.6/

Then i use untested_tkdnd_wrapper.py from http://stackoverflow.com/questions/1426 ... ry-widget/
to make use of tkdnd.

My debian details:
debian82(x86-64)
Cinnamon 2.2-16
Kernel 3.16.0-4-amd-64

I checked also permisssions and file type for so library inside tkdnd directory.
It was 64-bit. permission was rw for user.

I have verifyed that drag and drop works for QT applications in linux.
But my Tkinter python program did not crash, but just does not display (+) sign when dragging over tkinter windows and is not performing drag and drop.

Could not find where is the problem.
Also cannot really test if tkdnd works with raw tcl/tk script, because i do not know tcl language.

allankiipli
Posts: 4
Joined: 2016-01-07 12:00

Re: Need help with tkdnd package on debian linux

#2 Post by allankiipli »

Did little testing with different scripts and examples.
Turns out, that with simple example the difference of having drag and drop and not depends of the 'master' nesting in ui.

runs:
l = Tkinter.Listbox(root)
l.pack(side='top', fill='both', expand=1)

runs not:
f = Tkinter.Frame(master = root)
l = Tkinter.Listbox(f)
l.pack(side='top', fill='both', expand=1)

However with my complicated big program, the try to put one of the canvas items to root level, did not do the trick either.

Windows did not have this problem nor mac.
Seems that tcl is not nesting deep enough to direct tkdnd calls back to tkinter. This happens in linux.

Code: Select all

-------------------

if platform == "win32":
    os.environ['TKDND_LIBRARY'] = "C:\Python27\tcl\tkdnd2.8"

if platform == 'linux2':
    from DnD import DnD
else:
    from untested_tkdnd_wrapper import TkDND

class Dnd():
    def __init__(self, item, callback, dnd):
        self.item = item
        self.callback = callback
        self.dnd = dnd

    def drag(self, action, actions, type, win, X, Y, x, y, data):
        return action
        
    def drag_enter(self, action, actions, type, win, X, Y, x, y, data):
        self.item.focus_force()
        return action
    
    def drop(self, action, actions, type, win, X, Y, x, y, data):
        self.callback(None, self.item, X, Y, x, y, data)

    def bindtarget(self):
        self.dnd.bindtarget(self.item, 'text/uri-list', '<Drag>', self.drag, ('%A', '%a', '%T', '%W', '%X', '%Y', '%x', '%y', '%D'))
        self.dnd.bindtarget(self.item, 'text/uri-list', '<DragEnter>', self.drag_enter, ('%A', '%a', '%T', '%W', '%X', '%Y', '%x', '%y', '%D'))
        self.dnd.bindtarget(self.item, 'text/uri-list', '<Drop>', self.drop, ('%A', '%a', '%T', '%W', '%X', '%Y', '%x', '%y','%D'))

----------------

        if platform == 'linux2':
            self.embedbind = Dnd(self.embed, self.drag_to_canvas, dnd)
            self.embedbind.bindtarget()
        else:
            dnd.bindtarget(self.embed, self.drag_to_canvas, 'text/uri-list')

allankiipli
Posts: 4
Joined: 2016-01-07 12:00

Re: Need help with tkdnd package on debian linux

#3 Post by allankiipli »

Now i tested further, and found, that also adding menubar to the tkinter window,
blocks drag and drop occuring.
So i added a special drag and drop view to my application, without menubar and
canvas in it at top level, 'self' as parent.

It turns out that i cannot pass even proper coordiantes where the drop happened.
As a result i consider it incomplete. Unusable solution.

Code: Select all

import os
import sys
import threading
import re
import subprocess

pyversion = sys.version_info[0]

if pyversion < 3:
    import Tkinter as tk
else:
    import tkinter as tk

pyversion = sys.version_info[0]
platform = sys.platform
sysversion = sys.version

if platform == "win32":
    os.environ['TKDND_LIBRARY'] = "C:\Python27\tcl\tkdnd2.8"

if platform == 'linux2':
    from DnD import DnD
else:
    from tkdnd_wrapper import TkDND

class Dnd():
    def __init__(self, item, callback, dnd):
        self.item = item
        self.callback = callback
        self.dnd = dnd

    def drag(self, action, actions, type, win, X, Y, x, y, data):
        return action
        
    def drag_enter(self, action, actions, type, win, X, Y, x, y, data):
        self.item.focus_force()
        return action
    
    def drop(self, action, actions, type, win, X, Y, x, y, data):
        self.callback(None, self.item, X, Y, data)

    def bindtarget(self):
        self.dnd.bindtarget(self.item, 'text/uri-list', '<Drag>', self.drag, ('%A', '%a', '%T', '%W', '%X', '%Y', '%x', '%y', '%D'))
        self.dnd.bindtarget(self.item, 'text/uri-list', '<DragEnter>', self.drag_enter, ('%A', '%a', '%T', '%W', '%X', '%Y', '%x', '%y', '%D'))
        self.dnd.bindtarget(self.item, 'text/uri-list', '<Drop>', self.drop, ('%A', '%a', '%T', '%W', '%X', '%Y', '%x', '%y','%D'))

class DragAndDropWindow(tk.Toplevel):
    def __init__(self, parent = None, root = None, ok = None, refresh = None, T = "OK or not", canvas_w = None, canvas_h = None, dnd = None,
                 image = None, default = "OK", RWidth = None, RHeight = None, bg = None, ag = None, hg = None, fg = None):
        tk.Toplevel.__init__(self)
        self.parent = parent
        self.root = root
        self.callback = ok
        self.query_image = refresh
        self.RWidth = RWidth
        self.RHeight = RHeight
        self.title(T)
        self.image = image
        self.configure(takefocus = True, bg = bg)
        self.transient(self.parent)
        msg = tk.Message(self, text = default, width = 170, bg = bg)
        msg.pack(side = "top", fill = "x")
        self.canvas = tk.Canvas(self, width = canvas_w, height = canvas_h, bg = bg)
        self.canvas.create_image(0, 0, image = self.image, anchor = tk.NW, tags = "image")
        self.canvas.pack()

        if platform == 'linux2':
            self.canvasbind = Dnd(self.canvas, self.drag_to_canvas, dnd)
            self.canvasbind.bindtarget()
        else:
            dnd.bindtarget(self.canvas, self.drag_to_canvas, 'text/uri-list')

        self.bind('<Control-o>', lambda e = None: self.update_image())

        self.bind('<Escape>', lambda e = None: self.destroy())
        
        self.update()
        width = self.winfo_width()
        height = self.winfo_height()
        self.geometry(("%dx%d+%d+%d") % (width, height, 0, 0))
        self.focus_set()

    def lift_it(self, img):
        self.refresh_image(img)
        if platform == 'darwin':
            os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')
        if platform == 'cygwin':
            pass
        self.attributes('-topmost', 1)
        self.attributes('-topmost', 0)

    def update_image(self):
        img = self.query_image()
        self.refresh_image(img)

    def refresh_image(self, img):
        self.image = img
        self.canvas.delete("image")
        self.canvas.create_image(0, 0, image = self.image, anchor = tk.NW, tags = "image")
        self.canvas.update()

    def drag_to_canvas(self, event, widget = None, X = 0, Y = 0, data = None):
        print(widget, X, Y, data)
        self.callback(event, widget, X, Y, data)

allankiipli
Posts: 4
Joined: 2016-01-07 12:00

Re: Need help with tkdnd package on debian linux

#4 Post by allankiipli »

Final adjustments, and workaround in getting mouse coordinates inside drop view:
Here i just implement a special case, with both X and Y being string '0'.

Also in win32 environment i use TkDND wrapper and Tkinter event to proceed,
in linux it is DnD wrapper and it skips event parameter and submits parameters after event.

Code: Select all

    def drag_to_canvas(self, event, widget = None, X = 0, Y = 0, data = None):
        self.lock.acquire()
        print(data)
        if event is None:
            if X == '0' and Y == '0':
                X = widget.winfo_pointerx()
                Y = widget.winfo_pointery()
            x = int(X) - widget.winfo_rootx()
            y = int(Y) - widget.winfo_rooty()
            filename = data
        else:
            x = event.x_root - event.widget.winfo_rootx()
            y = event.y_root - event.widget.winfo_rooty()
            filename = event.data

Post Reply