Golang Tk9 Drag and Drop

 2025/11/26, 2025/11/26 -  ~

golang で tk9 を使って GUI アプリを作れるが、ドラッグアンドドロップする方法(windows)

python であれば、tkinterdnd2 を使えば、エクスプローラーからドラッグアンドドロップできるが、golang の modernc.org/tk9.0 ではできないのだろうか?

以下のようにすれば、可能なようである。

  1. MSYS2 UCRT64 シェルを起動する。
  2. tcl 9 のソースをコンパイルする
  3. tk 9 のソースをコンパイルする
  4. tkdnd のソースをコンパイルする。library の下の tkdnd_generic.tcl を修正する。
  5. golang のプログラムのほうで tkdnd を読み込ませる。ドラッグアンドドロップに応答する関数を記述する。

ボタン上にドラッグアンドドロップできるサンプルを置いておく。(PC保護のダイアログが表示されるため、気になる方は、go build -ldflags="-H windowsgui" してから実行してください。)

tcl / tk のコンパイル

ソースコードをダウンロードする。

展開して、それぞれのディレクトリ下で以下のようにする。(詳細な手順は省略…)

./configure --prefix=/opt/tcl9.0.2
make
make install

./configure --prefix=/opt/tk9.0.2
make
make install

tkdnd のコンパイル

https://github.com/petasis/tkdnd   を git clone しておく

./configure --with-tcl=/opt/tcl9.0.2/lib/ --with-tk=/opt/tk9.0.2/lib --prefix=/opt/tkdnd
make
make install

/opt/tcl9.0.2/lib/tkdnd2.9.5 を go アプリ下にコピーする。

コマンドプロンプトやエクスプローラーから実行する時は libwinpthread-1.dll が必要なようなので /ucrt64/lib/libwinpthread-1.dll も同じところにコピーする。

tkdnd_generic.tcl の修正

コピーした tkdnd2.9.5 フォルダ下にある、tkdnd_generic.tcl を修正する。

HandleDrop 関数の中を修正する。

$ diff -u /opt/tcl9.0.2/lib/tkdnd2.9.5/tkdnd_generic.tcl tkdnd_generic.tcl
--- /opt/tcl9.0.2/lib/tkdnd2.9.5/tkdnd_generic.tcl      2025-11-22 12:10:03.588767300 +0900
+++ tkdnd_generic.tcl   2025-11-24 10:05:07.850670000 +0900
@@ -416,6 +416,7 @@
       %L   \{$_typelist\}    %% % \
       %t   \{$_typelist\}    %T  \{[lindex $_common_drag_source_types 0]\} \
       %c   \{$_codelist\}    %C  \{[lindex $_codelist 0]\} \
+      %# 0 %K [join [lmap name $data { binary encode base64 [encoding convertto utf-8 $name]}] ","] %w 0 %h 0 %s 0\
       ] $cmd]
     set _action [uplevel \#0 $cmd]
   }

ここでは、Drop イベントの部分だけ修正している。

元のバージョンで modernc.org/tk9.0, tkdnd の組み合わせでうまく動かない理由を調べたところ、以下のようになっていた。

元のバージョンのままだと、以下のようなエラーになる。

eventDispatcher internal error: argv[1]="4 %# .button3 %K %w %h 21 11 1314 749 C:/Users/moriya/OneDrive/Desktop/aaa.log %s", err=newEvent: parsing event serial "%#": strconv.ParseInt: parsing "%#": invalid syntax

402 行目あたりに、

set cmd [bind $_drop_target <<Drop>>]

の行がある。ここで、tk コマンドのテンプレートが生成される。その下で %〜 に値をセットしているが、セットした文字列を modernc.org/tk9.0 に渡すと、go tk9 の tk.go newEvent 関数でうまく処理できない。

  1. %# がそのまま渡っているが、Int としてパースされてエラー
  2. %D にセットしているファイル一覧がアプリ側に渡らない

%# には 0 をセットしておく。

tkdnd は %D にファイル一覧をセットしている。しかし、bind で返ってくるパラメータは ドキュメント   によると、

%D
This reports the delta value of a MouseWheel event. The delta value represents the rotation units the mouse wheel has been moved. The sign of the value represents the direction the mouse wheel was scrolled.

となっている。modernc.org/tk9.0 では、Int として解釈している。そのため、引数が渡らない。

modernc.org/tk9.0 のソースを見たところ、%K %w %h などは、そのまま文字列が入るようだ。このいずれかを利用することにした。 また、tcl/tk のファイルリストは {{ファイル名}{ファイル名}…} のような形式になっている。スペースが入ったりすると go アプリ側にうまく渡せなかった。しかたないので、ファイル名を base64 エンコードして ‘,’ で結合して渡している。

上の HandleDrop 関数の修正では、%K を使用した。go アプリ側では、Keysym フィールドを使って値を読み出す。読み出した結果は、’,’ で分割して、base64 decode して元のファイル名に戻す。

まとめ

以上のようにすれば、windows 上で drag and drop を利用することは可能なようだ。

いつか公式に使えるようになればよいのですが。ちょっとしたアプリを作るのに、tk は手軽なので。