eBayに関わる作業を、PythonのWebツールを作ることで効率化することを考えていました。
しかし自分の技術力の無さから、やりたい事を実現するにはかなり時間がかかりそうだったので、とりあえず一部分はC#で作ることにしました。
C#やVBで、ツール系のアプリでよく使われるのがDataGridViewコントロールでしょう。
僕は、これの狙ったセルにファイルをドラッグ&ドロップして、そこにファイルパスを表示するというような事をやりたいと思っていました。しかしこれがなかなかうまく行きませんでした。
しばらく調べた後、うまく行かなかった原因と解決方法がわかったので、今日はそれを紹介します。
DragDropイベントの引数DragEventArgs eが持つ座標はスクリーン座標である
まず、「スクリーン座標」とは何ぞや?についてです。それに対するものとして「クライアント座標」というものがあります。
詳しくはこちらを見てみてください。ここに説明から解決方法まで書いてあるので、僕の話はこれ以上見る必要がないかもしれません。
要は、画面(ディスプレイ)の左上を起点とした座標がスクリーン座標で、フォームやボタンなどのコントロールの左上を起点とした座標がクライアント座標です。
さて、プロパティウィンドウからDragDropイベントをダブルクリックしてできるコードはこのようなものです。
private void dataGridView1_DragDrop(object sender, DragEventArgs e) { }
ネット上を検索すると、DataGridView上をクリックした際のセルの位置を取得するという例はいくつか見つかりました。
そして僕はこれを参考に、ドロップした際のセルの位置を取得するようにしました。ところがそうやって取得したセルの位置が何故かずれていました。
例えば、セル(2, 3)にファイルをドロップしたら、セル(5, 6)に値が入るとか。
結論を言うと、DragDropイベントの引数DragEventArgs eが持つ座標e.X、e.Yはスクリーン座標だったのに対して、MouseDownイベントの引数MouseEventArgs eが持つ座標e.X、e.Yはクライアント座標であるというだけでした。
DataGridViewへのドラッグ&ドロップはこれでバッチリ
という事で、こういうコードで解決できました。
private void dataGridView1_DragDrop(object sender, DragEventArgs e) { //スクリーン座標をクライアント座標に変換 Point pt = dataGridView1.PointToClient(new Point(e.X, e.Y)); DataGridView.HitTestInfo hti = dataGridView1.HitTest(pt.X, pt.Y); // ドラッグアンドドロップされたファイルのパス情報を取得します。 foreach (String filename in (string[])e.Data.GetData(DataFormats.FileDrop)) { // "filename" 変数に格納された、ドロップされたファイルのパスそれぞれについて、ここで処理を行います。 dataGridView1.Rows[hti.RowIndex].Cells[2].Value += filename + "\r\n"; } }
ドロップした行の左から2列目にファイルパスを追加するいうものです。
あとファイルをドラッグ&ドロップするための前提として、DragEnterイベントも追加しておいてください。
private void dataGridView1_DragEnter(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) { // ドラッグ中のファイルやディレクトリの取得 string[] drags = (string[])e.Data.GetData(DataFormats.FileDrop); foreach (string d in drags) { if (!System.IO.File.Exists(d)) { // ファイル以外であればイベント・ハンドラを抜ける return; } } e.Effect = DragDropEffects.Copy; } }
これについては、どこぞから拾ってきたソースをそのままコピペしただけです。
VBについても同様のはずです。これでハマっている人の参考になれば幸いです。