【Python】tkinter:ファイルのドラッグアンドドロップ(パス取得、画像表示)

2021.10.20 /

【Python】tkinter:ファイルのドラッグアンドドロップ(パス取得、画像表示)

本記事ではPythontkinterで、ファイルのドラッグアンドドロップを利用する方法について解説していきます。

具体的には、tkinterで起動したGUIアプリケーション上にファイルをドラッグアンドドロップして、ファイルのパスを取得画像を表示する方法を解説します。

tkinterでドラッグアンドドロップ機能を実装するために、TkinterDnD2というパッケージを利用します。

本記事では以下の環境でプログラムを実行しています。

  1. Python:3.8.8
  2. tkinterdnd2:0.3.0
  3. Anaconda:4.10.1

tkinterの基本的な使い方については以下記事からご参照ください。

本記事を通して以下の知識を学べます。

学べる知識
  • TkinterDnD2について
  • ドラッグアンドドロップ機能の実装方法
  • ウィジェット毎のドラッグアンドドロップ例

TkinterDnD2とは

TkinterDnD2はドラッグアンドドロップをtkinterアプリケーション上で可能にするライブラリです。

WindowsやUNIX、Macにドラッグアンドドロップ機能をTkに追加します。Python2とPython3の両方で利用できます。

ドラッグアンドドロップ機能で利用できるファイルは、テキストファイルやPDF、CSV、Word、Excelなど様々な拡張子が使えます。

TkinterDnD2は2021年10月現在では0.3.0が最新バージョンです。PyPIでのページは以下です。

PyPI – TkinterDnD2

2021年6月にPyPIに公開され、今はpipコマンドでTkinterDnD2をインストールできるようになりました。

pip install tkinterdnd2

上記pipによりパッケージフォルダ(anacondaだとAnaconda3\Lib\site-packages)に以下のパッケージが保存されます。

  1. tkdnd
  2. tkinterdnd2-0.3.0.dist-info
  3. tkinterdnd2

事前準備としてはpipコマンドでtkinterdnd2をインストールしておくだけです。

tkinterアプリにドラッグアンドドロップを実装する方法

tkinterによるGUIアプリケーションにドラッグアンドドロップを実装するには以下の項目を実行します。

  1. TkinterDnD2をインポート
  2. メインウィンドウをTkinterDnD.Tk()で生成
  3. ドロップターゲットの登録
  4. イベントと関数をウィジェットに紐づける

上記の各項目について詳しく解説していきます。

tkinterdnd2のインポート

最初のステップとして、Pythonスクリプトの先頭でtkinterとtkinterdnd2をインポートします。

from tkinter import *
from tkinterdnd2 import *

メインウィンドウの生成:TkinterDnD.Tk()

次にメインウィンドウを生成します。通常はtkinter.Tk()でメインウィンドウを作成します。

ここではアプリケーションにドラッグアンドドロップ機能を有効にするために、メインウィンドウをTkinterDnD.Tk()で作成します。

root = TkinterDnD.Tk()

これにより、メインウィンドウ及び子ウィジェットでドラッグアンドドロップに利用する特有のメソッドが各ウィジェットで使えるようになります。

ドロップターゲットの登録:drop_target_register()

次に対象のウィジェットをドロップターゲットとして登録します。
ドロップターゲットとは、ファイルのドロップアクションを受け入れることができるオブジェクト(ウィジェット)です。

ウィジェットをドロップターゲットにするために、drop_target_register()メソッドを利用します。

構文

drop_target_register(self, dndtypes)

引数のdndtypesでドロップアクションを受け入れるタイプを指定します。

指定できる値にDND_TextDND_Filesがあり、ファイルのドロップであればDND_Filesを指定します。

root.drop_target_register(DND_FILES)

イベントと関数を紐づける:dnd_bind()

対象のウィジェットに対して、トリガーとなる特定のイベントと実行する関数(コールバック関数)を紐づけます。

そのためにdnd_bind()メソッドを使用します。

構文

dnd_bind(self, sequence=None, func=None, add=None)

引数sequenceには指定した関数がどのイベントが発生したときに実行するかを指定します。指定できるイベントの一部を以下に記します。

イベント 説明
<<DropEnter>> ドラッグした状態のカーソルがウィジェット上にのったとき
<<DropPosition>> ドラッグした状態のカーソルがウィジェット上にのっているとき
<<DropLeave>> ドラックした状態のカーソルがウィジェットから離れたとき
<<Drop>> ウィジェット上でドロップしたとき

ウィジェット毎のドラッグアンドドロップ例

ここではドラッグアンドドロップ機能の使い方をウィジェットごとに解説していきます。

コードもすべて公開していますので、コピペして実際にどのように動作するのか確認してみてください。

Textウィジェット

Textウィジェットにドラッグアンドドロップ機能を追加します。

以下コードは、Textウィジェット上にドラッグしたテキストファイルをドロップすると、その内容を表示するアプリケーションです。

from tkinter import *
from tkinterdnd2 import *

def text_view(event):
    textarea.delete("1.0","end")
    if event.data.endswith(".txt"):
        with open(event.data, "r") as file:
            for line in file:
                line=line.strip()
                textarea.insert("end",f"{line}\n")

# メインウィンドウの生成
root = TkinterDnD.Tk()
root.title('テキストエディター')
root.geometry('400x300')
root.config(bg='#66ffff')
# フレームウィジェットの生成
frame = Frame(root)
# テキストウィジェットの生成
textarea = Text(frame, height=20, width=50)
textarea.drop_target_register(DND_FILES)
textarea.dnd_bind('<>', text_view)
# スクロールバーの生成
scroll = Scrollbar(frame, orient=VERTICAL)
textarea.configure(yscrollcommand=scroll.set)
scroll.config(command=textarea.yview)
# ウィジェットの配置
frame.pack()
textarea.pack(side=LEFT)
scroll.pack(side=RIGHT, fill=Y)

ws.mainloop()
tkinter:Textウィジェットにドラッグアンドドロップ機能を追加

Lavelウィジェット

Lavelウィジェットにドラッグアンドドロップ機能を追加します。

以下コードは、Lavelウィジェット上にドラッグしたファイルをドロップすると、そのファイルの絶対パスを表示するアプリケーションです。

import tkinter as tk
from tkinter import ttk
from tkinterdnd2 import *

def drop(event):
    print(event.data)
    text.set(event.data)

# メインウィンドウの生成
root = TkinterDnD.Tk()
root.geometry("400x100")
root.title("Lavelにドラッグアンドドロップ機能追加")
# StringVarのインスタンスを格納するウィジェット変数text
text = tk.StringVar(root)
text.set("ファイルをドロップするとファイルパスを表示します")
# Lavelウィジェットの生成
label = ttk.Label(root, textvariable=text)
label.drop_target_register(DND_FILES)
label.dnd_bind("<>", drop)
# ウィジェットの配置
label.grid(row=0, column=0, padx=10)

root.mainloop()
tkinter:Labelウィジェットにドラッグアンドドロップ機能を追加

Entryウィジェット

Entryウィジェットにドラッグアンドドロップ機能を追加します。

以下コードは、Entryウィジェット上にドラッグしたファイルをドロップすると、そのファイルの絶対パスを入力ボックス内に表示するアプリケーションです。

from tkinter import *
from tkinterdnd2 import *

def drop(event):
    var.set(event.data)

# メインウィンドウの生成
root = TkinterDnD.Tk()
root.title('Entryにドラッグアンドドロップ機能追加')
root.geometry('300x50')
root.config(bg='#fcba03')
# Lavelウィジェットの生成
label = Label(root, text='Folder Path', bg='#fcba03')
# Entryウィジェットの生成
var = StringVar()
entry = Entry(root, textvar=var, width=80)
entry.drop_target_register(DND_FILES)
entry.dnd_bind('<>', drop)
# ウィジェットの配置
label.pack(anchor=NW, padx=10)
entry.pack(fill=X, padx=10)

ws.mainloop()
tkinter:Entryウィジェットにドラッグアンドドロップ機能を追加

Listboxウィジェット

Listboxウィジェットにドラッグアンドドロップ機能を追加します。

以下コードは、Listboxウィジェット上にドラッグしたファイルをドロップすると、そのファイルの絶対パスをリストボックス内に表示するアプリケーションです。

ドロップしたファイルをリスト表示で下に随時追加していく仕様です。

from tkinter import *
from tkinterdnd2 import *

def add_listbox(event):
    listbox.insert("end", event.data)

# メインウィンドウの生成
root = TkinterDnD.Tk()
root.title('Listboxにドラッグアンドドロップ機能追加')
root.geometry('400x300')
root.config(bg='#cccccc')
# Frameウィジェットの生成
frame = Frame(root)
# Listboxウィジェットの生成
listbox = Listbox(frame, width=50, height=15, selectmode=SINGLE)
listbox.drop_target_register(DND_FILES)
listbox.dnd_bind('<>', add_listbox)
# スクロールバーの生成
scroll = Scrollbar(frame, orient=VERTICAL)
listbox.configure(yscrollcommand=scroll.set)
scroll.config(command=listbox.yview)
# ウィジェットの配置
frame.pack()
listbox.pack(fill=X, side=LEFT)
scroll.pack(side=RIGHT, fill=Y)

ws.mainloop()
tkinter:Listboxウィジェットにドラッグアンドドロップ機能を追加

Canvasウィジェット

Canvasウィジェットにドラッグアンドドロップ機能を追加します。

以下コードは、Canvasウィジェット上にドラッグした画像ファイルをドロップすると、その画像を表示するアプリケーションです。

from tkinter import *
from tkinterdnd2 import *
from PIL import Image, ImageTk

def drop(event):
    global display_image, canvas
    canvas.delete("image")
    img = Image.open(event.data)
    display_image = ImageTk.PhotoImage(img)
    canvas.create_image(0, 0, image = display_image, anchor = "nw")
    return event.action

# メインウィンドウの生成
display_image = None
root = TkinterDnD.Tk()
root.geometry("650x500")
root.title('Canvasにドラッグアンドドロップ機能追加')
root.drop_target_register(DND_FILES)
root.dnd_bind('<>', drop)
# Canvasウィジェットの生成
canvas = Canvas(root, width=640, height=480)
# ウィジェットの配置
canvas.pack()

root.mainloop()
tkinter:Canvasウィジェットにドラッグアンドドロップ機能を追加

まとめ

本記事「【Python】tkinter:ファイルのドラッグアンドドロップ(パス取得、画像表示)」はいかがでしたか。

tkinterで作成するGUIアプリケーションにドラッグアンドドロップ機能を実装できると、とても使いやすいアプリになります。

ぜひ本記事を参考にしてドラッグアンドドロップ機能を実装できるようになってください。