【間違った実装方法】 Windows Form(C#)のPictureBoxのカスタムコントロールにスクロールバーを付ける

ググってみると、
1.ユーザ・コントロールを作る。
2.中にPanelを追加する。
3.PanelはAutoScroll = true にする。
4.Panelの中にPictureBoxを置く。
と云う方法ばかり。
この方法の大きな利点は、Panelのプロパティやイベントをほぼそのまま継承し、都合の悪い場所だけoverrideしてるだけで手間がかからないこと。
※あえて言えば、Panelで未実装なのはドラッグ&ドロップと印刷ぐらいしかない。
この方法の大きな欠点は、PictureBoxのプロパティやイベントを泣きながら全部追加しなければいけなことだが、幸いなことにPictureBoxはしょぼいので、全くその心配は無い。
 
と云う訳で誰もやってそうもないので、ごく普通にPictureBoxのカスタムコントロールにスクロールバーを付けてみた。
この方法の大きな利点は、PictureBoxのプロパティやイベントをほぼそのまま継承し、都合の悪い場所だけoverrideしてるので、手間がかからないこと。
この方法の大きな欠点は、Panelのプロパティやイベントを泣きながら全部追加しなければいけなことだが、本当に困ったことにPanelは優秀で色々やってくれてるので非常にヤバイ!
※未実装は多数あります。
下記のカスタムコントロールをフォームに貼り、Anchor に Bottom, Right を追加するだけでも、未実装の場所はすぐバレる。
いや、フォームのデザイナー上でccPictireBox1のサイズを変えるだけでも判るくらいだ。(大笑
とは云え、どっちが楽なのかは、使い方次第。
 
一番大切なことはImageメソッドしか独自の機能が無いも同然のPictureBoxだからこそPanelを使う方が正解なのであって、何でもかんでも、スクロールバーを付けるならPanelという訳にはいかないことだ。
例えば、半端なく大量にメソッドやイベントがワンサカとありそうなSpreadSheetコントロールみたいなものでは、

  1. 大量にメソッドやイベントのプロパティやイベントを渡すだけのコードを泣きながらドンドン追加してしなければいけない。
  2. SpreadSheetコントロールのスクロールバーらしい動き(Excelっぽい動き)を誰もが期待するので、Panelのまんまの実装では誰(自分さえ)も納得しないから、ガリガリ書かないといけない。

ということになる。もちろんユーザコントロールにSpreadSheetメソッドを追加するだけで機能的なカスタムは可能だか、プロパティ・ウインドウで、色々いじることができないので、結局使う時に大変な目に遭ってしまう。
どれくらい大変なことになるかは、そんなSpreadSheetを貼り、色々設定した後のフォームのFormXXXX.Designer.csファイルを見れば、多分大量のコードとご対面するだろう。

※FormXXXX.Designer.csファイルにはこんな手書き厳禁の札がかかっている。
/// <summary>
/// デザイナー サポートに必要なメソッドです。このメソッドの内容を
/// コード エディターで変更しないでください。
/// </summary>
private void InitializeComponent()
{

そんな心配をすることは滅多にないだろう、第一そんなものを手掛ける優秀な方々が、ググって実装方法を検討なーんてする訳もないよね。(笑
だから、ここを見てしまった貴方。
素直に、ユーザ・コントロールにして、PanelコントロールにPictureBoxを載せた方が無難ですよ。
次回は、【正しい実装方法】 Windows Form(C#)のPictureBoxのカスタムコントロールに楽にスクロールバーを付ける
というのを書いてみたいな。
【参考にしてはいけない未完成のPictureBoxのスクロールバー付きカスタム・コントロールのソース】

using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace Custom.Control
{
 class ccPictureBox : PictureBox {
  //画像が大きい時に表示する
  VScrollBar sbV;
  HScrollBar sbH;
  float dx=0;
  float dy=0;
  /// <summary>
  /// コンストラクター
  /// </summary>
  public ccPictureBox() {
   sbV = new VScrollBar();
   sbV.Parent = this;
   sbV.Scroll += sbV_Scroll;
   sbV.Visible = false;
   sbH = new HScrollBar();
   sbH.Parent = this;
   sbH.Scroll += sbH_Scroll;
   sbH.Visible = false;
   this.DragDrop += new System.Windows.Forms.DragEventHandler(myDragDrop);
   this.DragEnter += new System.Windows.Forms.DragEventHandler(myDragEnter);
   ChkScrollBar();
  }
  /// <summary>
  /// 横スクロール時
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  void sbH_Scroll(object sender, ScrollEventArgs e) {
   dx = e.NewValue;
   this.Invalidate();
  }
  /// <summary>
  /// 縦スクロール時
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  void sbV_Scroll(object sender, ScrollEventArgs e) {
   dy = e.NewValue;
   this.Invalidate();
  }
  /// <summary>
  /// 描画時
  /// </summary>
  /// <param name="e"></param>
  protected override void OnPaint(PaintEventArgs e) {
   Graphics g = e.Graphics;
   g.TranslateTransform(-dx, -dy);
   GraphicsState bk = g.Save();
   base.OnPaint(e);
   g.Restore(bk);
  }
  /// <summary>
  ///
  /// </summary>
[Bindable(true)]
[Localizable(true)]
  public new Image Image {
   get {
    return base.Image;
   }
   set {
    base.Image = value;
    ChkScrollBar();
   }
  }
  /// <summary>
  ///
  /// </summary>
[Bindable(true)]
[Localizable(true)]
  public new Size Size {
   get {
    return base.Size;
   }
   set {
    base.Size = value;
    ChkScrollBar();
   }
  }
[DefaultValue(false), Browsable(true), Description("コントロールが、ユーザがドラッグしたデータを受け入れできるかを示します。"), Category("動作")]
  public override bool AllowDrop { get; set; }
  /// <summary>
  /// ドラッグ処理のイベントハンドラー
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private void myDragEnter(object sender, DragEventArgs e) {
   //ファイルならOKにしておく。
   if (e.Data.GetDataPresent(DataFormats.FileDrop)) {
    e.Effect = DragDropEffects.Copy;
   }
  }
  /// <summary>
  /// ドラッグ処理のイベントハンドラー
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private void myDragDrop(object sender, DragEventArgs e) {
   //ファイルなら
   if (e.Data.GetDataPresent(DataFormats.FileDrop)) {
    // ドラッグ中のファイルなどを取得
    string[] drags = (string[])e.Data.GetData(DataFormats.FileDrop);
    string fileName = null;
    foreach (string d in drags) {
     if (!System.IO.File.Exists(d)) {
      // ファイル以外であれば読み飛ばす。
      continue;
     }
     fileName = d;
    }
    if (fileName != null) {
     try {
      this.Image = Image.FromFile(fileName);
     } catch(Exception ex) {
      MessageBox.Show("【" + fileName + "】" + ex.Message);
     }
     e.Effect = DragDropEffects.Copy;
     ChkScrollBar();
    }
   }
  }
  /// <summary>
  /// スクロールバーを表示するかどうかチェックする
  /// </summary>
  /// <returns></returns>
  private bool ChkScrollBar() {
   bool rc=false;
   if (this.Image != null) {
    bool showV = (this.Height < this.Image.Size.Height);
    bool showH = (this.Width < this.Image.Size.Width);
    rc = showH | showH;
    //
    if (showV) {
     sbV.Top = 0;
     sbV.Left = this.Width - sbV.Width;
     sbV.Height = this.Height;
     //両方表示
     if (showH) {
      sbV.Height = this.Height - sbH.Height;
     }
     //
     sbV.Visible = true;
    } else {
     sbV.Visible = false;
    }
    if (showH) {
     sbH.Top = this.Height - sbH.Height;
     sbH.Left = 0;
     sbH.Width = this.Width;
     //両方表示
     if (showV) {
      sbH.Width = this.Width - sbV.Width;
     }
     //
     sbH.Visible = true;
     } else {
      sbH.Visible = false;
     }
    }
   return rc;
  }
 }
}
/// EOF.



コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA