TkinterでエクスプローラからDnDでファイルを受け取るアプリを作成してみようと思いました。
参考サイトの内容を元にコードを作成してみましたが、残念なことに 64bit Windows 10 ではうまく動作しません。
Python+TkでD&D -MasaHeroの日記より
http://d.hatena.ne.jp/MasaHero/20111201/p1
ctypesを使って、WindowsのDDLを直接操作しています。
32bit Windows7 にて、python 2.7 と 3.4で動作を確認しています。
これを64bit Windowsでも動作させるにはどのように修正すればよいでしょうか?
python
1# -*- coding: UTF-8 -*- 2# このスクリプトは OSのDDLを利用しているため、Windowsでのみ動作します。 3 4try: import Tkinter as tk 5except ImportError: import tkinter as tk 6import ctypes, sys 7from ctypes import c_long, WINFUNCTYPE 8from ctypes.wintypes import HWND, UINT, WPARAM, LPARAM 9 10WM_DROPFILES = 0x0233 11GWL_WNDPROC = -4 12FS_ENCODING = sys.getfilesystemencoding() 13 14DragAcceptFiles = ctypes.windll.shell32.DragAcceptFiles 15DragQueryFile = ctypes.windll.shell32.DragQueryFile 16DragFinish = ctypes.windll.shell32.DragFinish 17CallWindowProc = ctypes.windll.user32.CallWindowProcW 18GetWindowLong = ctypes.windll.user32.GetWindowLongW 19SetWindowLong = ctypes.windll.user32.SetWindowLongW 20 21 22class TkApp(tk.Frame): 23 dnd_interval = 600 24 25 def __init__(self, *args, **kargs): 26 tk.Frame.__init__(self, *args, **kargs) 27 self.createwidget() 28 self.dropnames = [] 29 win = args[0] if args else self._root() 30 win = self.tw 31 32 def drop_check(): 33 if self.dropnames: 34 fns = self.dropnames 35 self.dropnames = [] 36 self.dnd_notify(fns) 37 win.after(self.dnd_interval, drop_check) 38 39 40 @WINFUNCTYPE(c_long, HWND, UINT, WPARAM, LPARAM) 41 def replace_win_proc(hwnd, msg, wp, lp): 42 u"""D&D用のコールバック 43 ファイルのドラッグアンドドロップイベント(WM_DROPFILES)を検出して、 44 ドロップされたファイル名を保持する。 45 ここでウィンドウ(tk)を使用するとハングアップするのでデータ保存だけ行う。 46 """ 47 if msg == WM_DROPFILES: 48 nf = DragQueryFile(wp, -1, None, None) 49 buf = ctypes.c_buffer(260) 50 fns = [ buf.value.decode(FS_ENCODING) for nn in range(nf) \ 51 if DragQueryFile(wp, nn , buf, ctypes.sizeof(buf)) ] 52 DragFinish(wp) 53 self.dropnames.extend(fns) 54 print("%s dnd_notify: %s" % (self, hwnd)) 55 56 return CallWindowProc(self.org_proc, hwnd, msg, wp, lp) 57 58 59 def dnd_setup(): 60 "Windowsのイベント処理のフックを定義する" 61 hwnd = win.winfo_id() 62 DragAcceptFiles(hwnd, True) 63 self.org_proc = GetWindowLong(hwnd, GWL_WNDPROC) 64 self.win_proc = replace_win_proc 65 SetWindowLong(hwnd, GWL_WNDPROC, self.win_proc) 66 win.after_idle(drop_check) 67 print("%s dnd_setup: %s,%s" % (self, hwnd, self.org_proc)) 68 69 self.pack(fill='both', expand=1) 70 win.after_idle(dnd_setup) 71 72 73 def createwidget(self): 74 tw = tk.Text(self, width=30,height=16) 75 tw.pack(fill='both', expand=1) 76 self.tw = tw 77 78 79 def dnd_notify(self, filenames): 80 for nn in filenames: 81 self.tw.insert('end',"%s\n" % nn) 82 83 84if __name__ == "__main__": 85 a = TkApp() 86 if 0: TkApp(tk.Toplevel()) # 複数ウィンドウに対応 87 a.mainloop() 88
実行するとウィンドウが表示されます。そちらにエクスプローラからファイルやディレクトリをドロップすると、そのファイルのパスを表示(追記)します。
UNCでもうまく動作しているようです。
64bit Windows 10 では GetWindowLong の返り値が0になっているので、その辺りを調整すればよいのでは?と思うのですが..
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。