PictureBoxは画像ファイルのグラフィックスを表示するために使用されます。これに画像ファイルをドラッグアンドドロップするだけで画像を表示させることができるようにします。また大きな画像が表示されるときにはスクロールバーが表示されるようにします。
そのためにはソリューションエクスプローラからユーザーコントロールを追加します。スクロールバーがついたPictureBoxのようなものをつくるので名前はScrollPictureBoxにします。そして下の画像のように、ユーザーコントロールのうえにPictureBoxを貼り付けます。
PictureBoxにスクロールバーをつける
コンストラクタ内でユーザーコントロールのAutoScrollプロパティを trueにしてPictureBoxのSizeModeプロパティをPictureBoxSizeMode.AutoSizeに設定します。またPictureBoxの左上の座標を(0, 0)に設定します。これはコードに書かずにデザイナで設定してもかまいません。これで大きな画像が表示されるときはスクロールバーが表示されます。
1 2 3 4 5 6 7 8 9 10 11 |
public partial class ScrollPictureBox : UserControl { public ScrollPictureBox() { InitializeComponent(); pictureBox1.Location = new Point(0, 0); pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize; this.AutoScroll = true; } } |
ドラッグアンドドロップに対応させる
次に画像ファイルがドラッグアンドドロップされたときにPictureBoxにイメージを表示できるようにします。
なにかがScrollPictureBoxの上をドラッグされているとき、OnDragOverが呼び出されます。なにがドラッグされているかは引数のDragEventArgsを調べればわかります。
drgevent.Data.GetDataPresent(DataFormats.FileDrop)がtrueであればドラッグされているのはファイルかフォルダ(以降はファイル等と略す)です。ドラッグされているファイル等のパスは(string[])drgevent.Data.GetData(DataFormats.FileDrop)とすることでstring型の配列で取得できます。
配列が取得できたら、ファイル等の数が1であるかどうかを調べます。もし複数である場合は、複数の画像ファイルのイメージをひとつのPictureBoxに表示することはできないので無視します。
ひとつのファイル等がドラッグされていることがわかった場合はそれが画像ファイルかどうかを調べます。画像ファイルかどうかはImage.FromFile(path)を実行したときに戻り値が取得できるかで判断できます。フォルダであったりテキストファイルのような画像ファイルでない場合は例外が発生します。パスからimageが取得できた場合、そのままだとファイルがロックしてしまうのですぐにDisposeします。
これらの処理が滞りなくおこなわれた場合は、一つだけの画像ファイルがドラッグされていることになります。この場合はマウスポインタをコピーのマークに変更します。それ以外のときはドロップしても処理はおこないたくないので禁止のマークに変更します。drgevent.Effect = DragDropEffects.Copy;とすればコピー可のマークに変わり、drgevent.Effect = DragDropEffects.None;であれば禁止のマークに変化します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public partial class ScrollPictureBox : UserControl { protected override void OnDragOver(DragEventArgs drgevent) { bool isImageFile = false; if (drgevent.Data.GetDataPresent(DataFormats.FileDrop)) { string[] files = (string[])drgevent.Data.GetData(DataFormats.FileDrop); if (files.Length == 1) { string path = files[0]; try { Image image = Image.FromFile(path); image.Dispose(); isImageFile = true; } catch { } } } if (isImageFile) drgevent.Effect = DragDropEffects.Copy; else drgevent.Effect = DragDropEffects.None; base.OnDragOver(drgevent); } } |
次にドロップされたときの処理を示します。OnDragOverメソッドのなかで画像ファイルがひとつだけドラッグされている場合以外はdrgevent.Effect = DragDropEffects.None;としているので、画像ファイルがひとつだけドロップされた場合以外はOnDragDropメソッドは呼び出されません。そのためドロップされたものは画像ファイルがひとつだけという前提でおこなっています。
ファイルのパスからイメージを取得していますが、それをそのままPictureBox.Imageにセットしてしまうとそのファイルがロックされてしまいます。そこでこれをBitmapのコンストラクタに渡してコピーを取得し、ファイルのパスから直接取得したイメージはDisposeしています。そのあと生成したコピーをPictureBox.Imageにセットしています。
このときすでにPictureBoxになにかが表示されている場合はそれをDisposeする必要があります。そのためフィールド変数_imageにも同じものを保存しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public partial class ScrollPictureBox : UserControl { private Image? _image = null; protected override void OnDragDrop(DragEventArgs drgevent) { string[] files = (string[])drgevent.Data.GetData(DataFormats.FileDrop); Image image = Image.FromFile(files[0]); if (_image != null) _image.Dispose(); _image = new Bitmap(image); image.Dispose(); pictureBox1.Image = _image; base.OnDragDrop(drgevent); } } |
ところで大きな画像がPictureBoxに表示されている場合、ScrollPictureBoxは完全にPictureBoxに覆われているのでOnDragOverやOnDragDropは呼び出されるのかという疑問を感じるかもしれませんが、この場合もOnDragOverやOnDragDropは呼び出されます。
Imageプロパティの定義
それから外部からImageをセットすることでもPictureBoxに画像を表示できるようにします。そのためにImageプロパティを定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class ScrollPictureBox : UserControl { public Image? Image { get { return _image; } set { if (_image != null) _image.Dispose(); _image = value; pictureBox1.Image = _image; } } } |
デザイナのツールボックスをみるとScrollPictureBoxが追加されていることがわかります。これをツールボックスからFormにドラッグアンドドロップすると他のコントロールと同様に使うことができます。