tkinterでドラッグ&ドロップ


Python付属のIDLEは、ファイルをウィンドウにD&Dしても、
そのファイルを開いてくれない。
それは、tkinterにドラッグ&ドロップがまだ完全には実装されていないからだ。



しかし、tcl/tkには既にtkDNDと言うものがあり、ちゃんとファイルをD&Dできる。
tkinterはtcl/tkをPythonから呼び出す仕組みであるから、
それを通してtclにtkDNDを呼び出させれば、PythonでもD&Dできる。



http://sourceforge.net/projects/tkdnd/
から、TkDND 2.0 Alphaをダウンロードし解凍する。

library、pkgIndex.tcl、libtkdnd20.so、libtkdnd20.dllを、C:\Python30\Tcl\tkdndと言うフォルダを作って、そこにコピーする。



とりあえず、次のようなコードでドラッグ&ドロップが出来るようだ。

#python3.0以降用
from pprint import pprint
from tkinter import * #Python2.xならfrom Tkinter import *

def attributesFromDict(d, self=None):
    if self == None:
        self = d.pop("self")
    for n,v in d.items():
        setattr(self , n , v)

def main():
    root = Tk()
    root.tk.call("package", "require", "tkdnd")
    
    w = Text(height=25, width=50)
    w.pack(side="left", padx=2, pady=2, fill="y", expand=0)
    
    def callback(event):
        pprint(event.__dict__)
    
    class DndEvent(Event):
        """A TkDND Event"""
        def __init__(self, event, widget, x, y,
              source_types, target_types, 
              source_actions, action, common_source_types,
              common_target_types, types, drop_type,
              pressed_keys, data):
              
              super(DndEvent, self).__init__()
              attributesFromDict(locals())
            
        def __repr__(self):
              return "" % (self.action,
                                           self.type)
    
    _dnd_subst_format_str = "%e %W %X %Y %ST %TT %a %A" \
                            " %CST %CTT %t %T %b %D"
    
    def _dnd_substitute(e, W, X, Y, ST, TT, a, 
        A, CST, CTT, t, T, b, D):
        X = int(X)
        Y = int(Y)
        D = root.tk.splitlist(D)
        ev = DndEvent(e, W, X, Y, ST, TT, a, A, 
                      CST, CTT, t, T, b, D)
        return (ev,)
        
    funcid = root._register(callback, _dnd_substitute,
                            needcleanup=1)
    event = '''[%s %s]''' %(funcid,
                            _dnd_subst_format_str)
    types = "CF_HDROP"#Windowsでのファイルの
    #types = "CF_TEXT"#Windowsでのテキストの
    #types = "*"#なんでも
    root.tk.call("tkdnd::drop_target", "register", 
                  w, types)
    root.tk.call("bind", w, "<>", event)
    root.mainloop()
    
if __name__ == "__main__":
    main()


とりあえず、IDLEにドラッグ&ドロップをつけてみようかな?