将网址从浏览器拖放到文本字段(tkinter或kivy)中

时间:2018-11-28 09:01:55

标签: python tkinter kivy

因此,我试图将URL从浏览器(chrome)中拖到文本框中。

这是Tkinter文本框的图像: Tkinter Text box image

使用相同的方法将URL拖动到Word中,然后将其“粘贴”到文本区域中。

例如图片:

print screen

在带有wx.TextDropTarget的wxPython中这是可能的,但是如何在Tkinter中完成呢?

在Tkinter中有没有办法做到这一点?

1 个答案:

答案 0 :(得分:0)

所以您需要跳过一些箍,但是您想要的是可能的。 使用this answer中的信息,我已经能够在带有64位python 3.7.1的Windows 10 64位上运行此功能

首先,我从here下载了相关的二进制文件,在我的情况下为tkdnd2.8-win32-x86_64.tar.gz

我解压缩了这个文件,得到一个名为tkdnd2.8的文件夹,并将其放在以下位置:

C:\Program Files\Python37\tcl

这意味着它可以很容易地被tk解释器找到,您可以将其放在其他位置,但是您需要将路径添加到环境变量中才能找到它。

然后我从该答案中使用了包装器(但已将tk更新为python 3名称):

import os
import tkinter

def _load_tkdnd(master):
    tkdndlib = os.environ.get('TKDND_LIBRARY')
    if tkdndlib:
        master.tk.eval('global auto_path; lappend auto_path {%s}' % tkdndlib)
    master.tk.eval('package require tkdnd')
    master._tkdnd_loaded = True


class TkDND(object):
    def __init__(self, master):
        if not getattr(master, '_tkdnd_loaded', False):
            _load_tkdnd(master)
        self.master = master
        self.tk = master.tk

    # Available pre-defined values for the 'dndtype' parameter:
    #   text/plain
    #   text/plain;charset=UTF-8
    #   text/uri-list

    def bindtarget(self, window, callback, dndtype, event='<Drop>', priority=50):
        cmd = self._prepare_tkdnd_func(callback)
        return self.tk.call('dnd', 'bindtarget', window, dndtype, event,
                cmd, priority)

    def bindtarget_query(self, window, dndtype=None, event='<Drop>'):
        return self.tk.call('dnd', 'bindtarget', window, dndtype, event)

    def cleartarget(self, window):
        self.tk.call('dnd', 'cleartarget', window)


    def bindsource(self, window, callback, dndtype, priority=50):
        cmd = self._prepare_tkdnd_func(callback)
        self.tk.call('dnd', 'bindsource', window, dndtype, cmd, priority)

    def bindsource_query(self, window, dndtype=None):
        return self.tk.call('dnd', 'bindsource', window, dndtype)

    def clearsource(self, window):
        self.tk.call('dnd', 'clearsource', window)


    def drag(self, window, actions=None, descriptions=None,
            cursorwin=None, callback=None):
        cmd = None
        if cursorwin is not None:
            if callback is not None:
                cmd = self._prepare_tkdnd_func(callback)
        self.tk.call('dnd', 'drag', window, actions, descriptions,
                cursorwin, cmd)


    _subst_format = ('%A', '%a', '%b', '%D', '%d', '%m', '%T',
            '%W', '%X', '%Y', '%x', '%y')
    _subst_format_str = " ".join(_subst_format)

    def _prepare_tkdnd_func(self, callback):
        funcid = self.master.register(callback, self._dndsubstitute)
        cmd = ('%s %s' % (funcid, self._subst_format_str))
        return cmd

    def _dndsubstitute(self, *args):
        if len(args) != len(self._subst_format):
            return args

        def try_int(x):
            x = str(x)
            try:
                return int(x)
            except ValueError:
                return x

        A, a, b, D, d, m, T, W, X, Y, x, y = args

        event = tkinter.Event()
        event.action = A       # Current action of the drag and drop operation.
        event.action_list = a  # Action list supported by the drag source.
        event.mouse_button = b # Mouse button pressed during the drag and drop.
        event.data = D         # The data that has been dropped.
        event.descr = d        # The list of descriptions.
        event.modifier = m     # The list of modifier keyboard keys pressed.
        event.dndtype = T
        event.widget = self.master.nametowidget(W)
        event.x_root = X       # Mouse pointer x coord, relative to the root win.
        event.y_root = Y
        event.x = x            # Mouse pointer x coord, relative to the widget.
        event.y = y

        event.action_list = str(event.action_list).split()
        for name in ('mouse_button', 'x', 'y', 'x_root', 'y_root'):
            setattr(event, name, try_int(getattr(event, name)))

        return (event, )

然后是一个简单的测试脚本:

import tkinter
from TkDND2 import TkDND

root = tkinter.Tk()

dnd = TkDND(root)

entry = tkinter.Entry()
entry.pack()

def handle(event):
    event.widget.insert(0, event.data)

dnd.bindtarget(entry, handle, 'text/plain')

root.mainloop()

请注意,我调用了包装程序TkDND2,以免与内置的dnd混淆。

通过更改bindtarget的最后一个参数,您可以更改接受的输入类型,其中text/plain的大多数文本输入应从任何程序接受,而text/uri-list只允许将文件从资源管理器中拖动到文本输入中并获取该文件的路径,IE中的URL无效。

还请注意,要在sourceforge上下载的文件已经过时了,但是我唯一可以下载预先构建的二进制发行版的地方。

编辑:

我对在其他地方找到的包装器不满意,因此我对其进行了修改,以便对tkinter中所有内容的Widget类进行修补,例如,您可以使用{{1} }。

entry.bindtarget(callback, type)

示例用法:

import os
import tkinter

__all__ = ['Text', 'Files', 'URL', 'HTML', 'RTF']

# the types of drop supported content
Text = 'DND_Text'
Files = 'DND_Files'
URL = 'DND_URL'
HTML = 'DND_HTML'
RTF = 'DND_RTF'

def drop_entry(event):
    event.widget.insert(0, event.data)

def drop_text(event):
    event.widget.insert(1.0, event.data)

def _load_tkdnd(master):
    if not getattr(master, '_tkdnd_loaded', False):
        tkdndlib = os.environ.get('TKDND_LIBRARY')
        if tkdndlib:
            master.tk.eval('global auto_path; lappend auto_path {%s}' % tkdndlib)
        master.tk.eval('package require tkdnd')
        master._tkdnd_loaded = True

def bindtarget(self, callback=None, dndtype=Text, event='<Drop>', priority=50):
    if callback == None:
        classnames = [x.__name__ for x in self.__class__.__bases__]
        classnames.append(self.__class__.__name__)
        print(classnames)
        if 'Entry' in classnames:
            callback = drop_entry
        elif 'Text' in classnames:
            callback = drop_text
        else:
            raise ValueError('No default callback')
    _load_tkdnd(self)
    cmd = self._prepare_tkdnd_func(callback)
    return self.tk.call('dnd', 'bindtarget', self, dndtype, event, cmd, priority)

def bindtarget_query(self, dndtype=None, event='<Drop>'):
    _load_tkdnd(self)
    return self.tk.call('dnd', 'bindtarget', self, dndtype, event)

def cleartarget(self):
    _load_tkdnd(self)
    return self.tk.call('dnd', 'cleartarget', self)

def bindsource(self, callback, dndtype, priority=50):
    _load_tkdnd(self)
    cmd = self._prepare_tkdnd_func(callback)
    return self.tk.call('dnd', 'bindsource', self, dndtype, cmd, priority)

def bindsource_query(self, dndtype=None):
    _load_tkdnd(self)
    return self.tk.call('dnd', 'bindsource', self, dndtype)

def clearsource(self):
    return self.tk.call('dnd', 'clearsource', self)

def drag(self, actions=None, descriptions=None, cursorwin=None, callback=None):
    cmd = None
    if cursorwin is not None:
        if callback is not None:
            cmd = self._prepare_tkdnd_func(callback)
    return self.tk.call('dnd', 'drag', self, actions, descriptions, cursorwin, cmd)

_subst_format = ('%A', '%a', '%b', '%D', '%d', '%m', '%T', '%W', '%X', '%Y', '%x', '%y')
_subst_format_str = " ".join(_subst_format)

def _prepare_tkdnd_func(self, callback):
    funcid = self.master.register(callback, self._dndsubstitute)
    cmd = ('%s %s' % (funcid, _subst_format_str))
    return cmd

def _dndsubstitute(self, *args):
    if len(args) != len(_subst_format):
        return args

    def try_int(x):
        x = str(x)
        try:
            return int(x)
        except ValueError:
            return x

    A, a, b, D, d, m, T, W, X, Y, x, y = args

    event = tkinter.Event()
    event.action = A       # Current action of the drag and drop operation.
    event.action_list = a  # Action list supported by the drag source.
    event.mouse_button = b # Mouse button pressed during the drag and drop.
    event.data = D         # The data that has been dropped.
    event.descr = d        # The list of descriptions.
    event.modifier = m     # The list of modifier keyboard keys pressed.
    event.dndtype = T
    event.widget = self    # The widget that recieved the event
    event.x_root = X       # Mouse pointer x coord, relative to the root win.
    event.y_root = Y
    event.x = x            # Mouse pointer x coord, relative to the widget.
    event.y = y

    event.action_list = str(event.action_list).split()
    for name in ('mouse_button', 'x', 'y', 'x_root', 'y_root'):
        setattr(event, name, try_int(getattr(event, name)))
    return (event, )

tkinter.Widget.bindtarget = bindtarget
tkinter.Widget.bindtarget_query = bindtarget_query
tkinter.Widget.cleartarget = cleartarget
tkinter.Widget.bindsource = bindsource
tkinter.Widget.bindsource_query = bindsource_query
tkinter.Widget.clearsource = clearsource
tkinter.Widget.drag = drag
tkinter.Widget._prepare_tkdnd_func = _prepare_tkdnd_func
tkinter.Widget._dndsubstitute = _dndsubstitute

这还为简单的小部件(输入,文本和后代)添加了一些默认回调,因此如示例所示,可以在不带参数的情况下调用它们。