■ はじめに
PictureBox + HScrollBar / VScrollBar でのアプリ実装は大変なので、 別の方法を考えるHScrollBar / VScrollBar ~ 独自スクロールバーの実装 ~
https://blogs.yahoo.co.jp/dk521123/38010582.html
■ サンプル
例1:シンプルなサンプル
画面の構成+ panel (Panelを画像の親コントロールとして配置する) + pictureBox (PictureBoxをPanelの子として配置する。親とドッキングしないこと)プロパティの変更
+ panel - Ancher : Top, Bottom, Left, Right - AutoScroll : TrueForm1.cs
using System; using System.Drawing; using System.Windows.Forms; namespace SampleForm { public partial class Form1 : Form { private Bitmap bitmap; public Form1() { this.bitmap = new Bitmap(@"C:\temp\20161215052204.gif"); InitializeComponent(); } // ロード private void Form1_Load(object sender, EventArgs e) { this.pictureBox1.Size = this.bitmap.Size; this.pictureBox1.Refresh(); } // リサイズ private void Form1_Resize(object sender, EventArgs e) { this.pictureBox1.Refresh(); } // スクロール private void panel1_Scroll(object sender, ScrollEventArgs e) { this.pictureBox1.Refresh(); } private void pictureBox1_Paint(object sender, PaintEventArgs e) { // スクロールバー位置より元画像を切り抜いて表示 Console.WriteLine(string.Format( "{0}, {1}, {2}, {3}", this.panel1.HorizontalScroll.Value, this.panel1.VerticalScroll.Value, this.panel1.ClientSize.Width, this.panel1.ClientSize.Height)); e.Graphics.DrawImage( this.bitmap, new Rectangle(this.panel1.HorizontalScroll.Value, this.panel1.VerticalScroll.Value, this.panel1.ClientSize.Width, this.panel1.ClientSize.Height), this.panel1.HorizontalScroll.Value, this.panel1.VerticalScroll.Value, this.panel1.ClientSize.Width, this.panel1.ClientSize.Height, GraphicsUnit.Pixel); } } }
例2:例1 + ドラッグ移動を追加
https://blogs.yahoo.co.jp/dk521123/37861699.htmlの「例1:AutoScrollPositionを利用する」を追加するForm1.cs
using System; using System.Drawing; using System.Windows.Forms; namespace SampleForm { public partial class Form1 : Form { private Bitmap bitmap; private Point startPoint = Point.Empty; private bool IsDragging { get { return !this.startPoint.IsEmpty; } } public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { this.bitmap = new Bitmap(@"C:\temp\20161215052204.gif"); this.pictureBox1.Size = this.bitmap.Size; this.pictureBox1.Refresh(); } // リサイズ private void Form1_Resize(object sender, EventArgs e) { this.pictureBox1.Refresh(); } // スクロール private void panel1_Scroll(object sender, ScrollEventArgs e) { this.pictureBox1.Refresh(); } private void pictureBox1_Paint(object sender, PaintEventArgs e) { // スクロールバー位置より元画像を切り抜いて表示 Console.WriteLine(string.Format( "{0}, {1}, {2}, {3}", this.panel1.HorizontalScroll.Value, this.panel1.VerticalScroll.Value, this.panel1.ClientSize.Width, this.panel1.ClientSize.Height)); e.Graphics.DrawImage( this.bitmap, new Rectangle(this.panel1.HorizontalScroll.Value, this.panel1.VerticalScroll.Value, this.panel1.ClientSize.Width, this.panel1.ClientSize.Height), this.panel1.HorizontalScroll.Value, this.panel1.VerticalScroll.Value, this.panel1.ClientSize.Width, this.panel1.ClientSize.Height, GraphicsUnit.Pixel); } private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { this.pictureBox1.Focus(); this.startPoint = e.Location; } private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { if (!this.IsDragging) { return; } var movementPoint = new Point( e.Location.X - this.startPoint.X, e.Location.Y - this.startPoint.Y); this.panel1.AutoScrollPosition = new Point( -panel1.AutoScrollPosition.X - movementPoint.X, -panel1.AutoScrollPosition.Y - movementPoint.Y); } private void pictureBox1_MouseUp(object sender, MouseEventArgs e) { this.startPoint = Point.Empty; } } }
例3:アフィン変換でのドラッグ移動+拡大縮小機能
https://blogs.yahoo.co.jp/dk521123/37866101.htmlhttps://blogs.yahoo.co.jp/dk521123/38061211.html
をベースに実装するForm1.cs
using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Windows.Forms; namespace SampleForm { public partial class Form1 : Form { // アフィン変換 private Matrix affineTransformation = new Matrix(); private Bitmap targetBitmap; // 描画元を指定する4点の座標(左上、右上、左下、右下の順) private PointF[] sourcePoints; private Point startPoint = Point.Empty; private Point oldPoint = Point.Empty; private bool IsDragging { get { return !this.oldPoint.IsEmpty; } } public Form1() { InitializeComponent(); // ホイールイベントの追加 this.pictureBox1.MouseWheel += new MouseEventHandler(this.pictureBox1_MouseWheel); } private void Form1_Load(object sender, EventArgs e) { this.OpenImageFile(@"C:\temp\20161215052204.gif"); } // マウスホイールイベント private void pictureBox1_MouseWheel(object sender, MouseEventArgs e) { this.affineTransformation.Translate(-e.X, -e.Y, MatrixOrder.Append); if (e.Delta > 0) { // 拡大 if (this.affineTransformation.Elements[0] < 100) { this.affineTransformation = this.GetAffineTransformationToScale( this.affineTransformation, 1.5f, e.Location); } } else { // 縮小 if (this.affineTransformation.Elements[0] > 0.01) { this.affineTransformation = this.GetAffineTransformationToScale( this.affineTransformation, 1.0f / 1.5f, e.Location); } } this.affineTransformation.Translate(e.X, e.Y, MatrixOrder.Append); this.DrawImage(); } // リサイズ private void Form1_Resize(object sender, EventArgs e) { this.ResizePictureBox(); } // スクロール private void panel1_Scroll(object sender, ScrollEventArgs e) { this.ResizePictureBox(); } private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { this.pictureBox1.Focus(); this.startPoint = e.Location; this.oldPoint = this.startPoint; } private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { if (!this.IsDragging) { return; } // 移動 this.affineTransformation.Translate( e.X - this.oldPoint.X, e.Y - this.oldPoint.Y, MatrixOrder.Append); this.DrawImage(); this.oldPoint = e.Location; var movementPoint = new Point( e.Location.X - this.startPoint.X, e.Location.Y - this.startPoint.Y); this.panel1.AutoScrollPosition = new Point( -panel1.AutoScrollPosition.X - movementPoint.X, -panel1.AutoScrollPosition.Y - movementPoint.Y); } private void pictureBox1_MouseUp(object sender, MouseEventArgs e) { this.startPoint = Point.Empty; this.oldPoint = Point.Empty; } private void OpenImageFile(string imageFilePath) { if (string.IsNullOrEmpty(imageFilePath)) { return; } // 画像ファイルのImageオブジェクトを作成する this.targetBitmap = new Bitmap(imageFilePath); this.pictureBox1.Size = this.targetBitmap.Size; var sourceArea = new RectangleF(-0.5f, -0.5f, this.targetBitmap.Width, this.targetBitmap.Height); // 描画元を指定する4点の座標(左上、右上、左下、右下の順) this.sourcePoints = new PointF[4]; this.sourcePoints[0] = new PointF(sourceArea.Left, sourceArea.Top); this.sourcePoints[1] = new PointF(sourceArea.Right, sourceArea.Top); this.sourcePoints[2] = new PointF(sourceArea.Left, sourceArea.Bottom); this.sourcePoints[3] = new PointF(sourceArea.Right, sourceArea.Bottom); this.DrawImage(); } private void ResizePictureBox() { if (this.targetBitmap == null || (this.pictureBox1.Width == 0) || (this.pictureBox1.Height == 0)) { return; } this.DrawImage(); } private Matrix GetAffineTransformationToScale(Matrix matrix, float scale, Point point) { matrix.Translate(-point.X, -point.Y, MatrixOrder.Append); matrix.Scale(scale, scale, MatrixOrder.Append); matrix.Translate(point.X, point.Y, MatrixOrder.Append); return matrix; } // ビットマップの描画 private void DrawImage() { if (this.pictureBox1.Width == 0 || this.pictureBox1.Height == 0) { return; } // 描画先の座標をアフィン変換で求める(左上、右上、左下の順) var destinationPoints = (PointF[])this.sourcePoints.Clone(); // 描画先の座標をアフィン変換で求める(変換後の座標は上書きされる) this.affineTransformation.TransformPoints(destinationPoints); this.Text = string.Format( "({0:#.#}, {1:0.#}), ({2:#.#}, {3:0.#}), ({4:#.#}, {5:0.#}), ({6:#.#}, {7:0.#})", destinationPoints[0].X, destinationPoints[0].Y, destinationPoints[1].X, destinationPoints[1].Y, destinationPoints[2].X, destinationPoints[2].Y, destinationPoints[3].X, destinationPoints[3].Y); float minX = destinationPoints.Min(point => point.X); float maxX = destinationPoints.Max(point => point.X); float minY = destinationPoints.Min(point => point.Y); float maxY = destinationPoints.Max(point => point.Y); // 画像の幅と高さ int imageWidth = (int)Math.Ceiling(maxX - minX); int imageHeight = (int)Math.Ceiling(maxY - minY); this.pictureBox1.Width = imageWidth; this.pictureBox1.Height = imageHeight; Bitmap clonedBitmap = new Bitmap(this.pictureBox1.Width, this.pictureBox1.Height); using (var graphics = Graphics.FromImage(clonedBitmap)) { // まずは背景色を黒くする graphics.Clear(Color.Black); graphics.Transform = this.affineTransformation; // 高品質双三次補間を指定 graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; // 描画(指定された位置に元の物理サイズで描画) graphics.DrawImageUnscaled(targetBitmap, 0, 0); } // 描画 if (this.pictureBox1.Image != null) { this.pictureBox1.Image.Dispose(); } this.pictureBox1.Image = clonedBitmap; this.pictureBox1.Refresh(); } } }
関連記事
Windows Form
Windows Form ~ 目次 ~https://blogs.yahoo.co.jp/dk521123/8054245.html
Panel / ScrollableControl
https://blogs.yahoo.co.jp/dk521123/38013080.html
HScrollBar / VScrollBar ~ 独自スクロールバーの実装 ~
https://blogs.yahoo.co.jp/dk521123/38010582.html
スクロール に関するあれこれ
https://blogs.yahoo.co.jp/dk521123/37838702.html
Windows Form / PictureBox
PictureBox [3] ~ マウスホイール で画像の拡大・縮小する ~https://blogs.yahoo.co.jp/dk521123/37866101.html
その他
画像処理 ~ アフィン変換・Matrixクラス ~https://blogs.yahoo.co.jp/dk521123/38061211.html