C#で2枚の画像を表示する。【WinForms】2

コンピュータ

表示画像を移動させる機能を付与しようとしましたが、前回作成のプログラムをベースに変更しようと試みましたが断念し、全面的に書き直しました。

前回の記事

プロジェクトの作成

mkdir プロジェクト名
cd プロジェクト名
dotnet new winforms -f net6.0

ソースコード

ファイル名:Form1.cs

using System.Drawing.Drawing2D;

namespace DualViewer2;

public partial class Form1 : Form
{
    // 定数
    const int _margin = 10;

    // 右側のBitmap
    Bitmap? rightBitmap = null;
    // 右側のGrapichs
    Graphics? rightGraphics = null;
    // 右側のMatrix
    Matrix? rightMatrix = null;
    // 右側のマウス移動フラグ
    bool rightIsMouseMoving = false;
    // 右側のマウス座標
    PointF rightMousePostion = new();
    // 左側のBitmap
    Bitmap? leftBitmap = null;
    // 左側のGrapichs
    Graphics? leftGraphics = null;
    // 左側のMatrix
    Matrix? leftMatrix = null;
    // 左側のマウス移動フラグ
    bool leftIsMouseMoving = false;
    // 左側のマウス座標
    PointF leftMousePostion = new();
    // 左パネル
    readonly Panel leftPanel = new()
    {
        BackColor = Color.LightBlue,
    };
    // 左ピクチャボックス
    readonly PictureBox leftView = new()
    {
        Dock = DockStyle.Fill,
        BackColor = Color.Blue,
        AllowDrop = true,
    };
    // 右パネル
    readonly Panel rightPanel = new()
    {
        BackColor = Color.LightGreen,
    };
    // 右ピクチャボックス
    readonly PictureBox rightView = new()
    {
        Dock = DockStyle.Fill,
        BackColor = Color.Green,
        AllowDrop = true,
    };
    // コンストラクタ
    public Form1()
    {
        // コンポーネント初期化
        InitializeComponent();

        // イベントの登録
        this.Load += Form1_Load;
        this.Resize += Form1_Resize;

        leftView.DragEnter += LeftView_DragEnter;
        leftView.DragDrop += LeftView_DragDrop;
        rightView.DragEnter += RightView_DragEnter;
        rightView.DragDrop += RightView_DragDrop;

        rightView.MouseDown += View_MouseDown;
        rightView.MouseMove += View_MouseMove;
        rightView.MouseUp += View_MouseUp;
        rightView.MouseWheel += View_MouseWheel;

        leftView.MouseDown += View_MouseDown;
        leftView.MouseMove += View_MouseMove;
        leftView.MouseUp += View_MouseUp;
        leftView.MouseWheel += View_MouseWheel;

    }
    // フォームロードイベント
    void Form1_Load(object? s, EventArgs e)
    {
        rightPanel.Controls.Add(rightView);
        leftPanel.Controls.Add(leftView);
        this.Controls.AddRange(new Control[]{leftPanel, rightPanel});
        this.Size = new Size(800, 600);
    }
    // フォームのリサイズイベント
    void Form1_Resize(object? s, EventArgs e)
    {
        int width = this.ClientSize.Width;
        int height = this.ClientSize.Height;
        if (width == 0 || height == 0) return;

        int w = (width - (_margin * 4)) / 2;
        int h = (height - (_margin * 2));

        leftPanel.Location = new Point(_margin, _margin);
        leftPanel.Size = new Size(w, h);

        rightPanel.Location = new Point(_margin*2 + w, _margin);
        rightPanel.Size = new Size(w, h);

        if (rightGraphics is not null) {
            rightMatrix = rightGraphics.Transform;
            rightGraphics.Dispose();
        }
        else
            rightMatrix = new Matrix();
        
        rightView.Image?.Dispose();
        rightView.Image = new Bitmap(rightView.Width, rightView.Height);
        rightGraphics = Graphics.FromImage(rightView.Image);
        rightGraphics.InterpolationMode = InterpolationMode.NearestNeighbor;

        leftView.Image?.Dispose();
        leftView.Image = new Bitmap(leftView.Width, leftView.Height);
        leftGraphics = Graphics.FromImage(leftView.Image);
        leftGraphics.InterpolationMode = InterpolationMode.NearestNeighbor;

        DrawImage();
    }
    // 左ビュードラグアンドドロップ
    void LeftView_DragEnter(object? s, DragEventArgs e)
    {
        e.Effect = DragDropEffects.All;
    }
    async void LeftView_DragDrop(object? s, DragEventArgs e)
    {
        if (e.Data == null) return;
        Object? obj = e.Data.GetData(DataFormats.FileDrop, false);
        if (obj == null) return;
        var path = ((string[])obj)[0];

        using var fs = new FileStream(path, FileMode.Open, FileAccess.Read);
        leftBitmap?.Dispose();
        leftBitmap = await Task.Run(()=>(Bitmap)Bitmap.FromStream(fs));
        rightMatrix?.Reset();
        leftMatrix = new Matrix();
        DrawImage();
    }
    // 右ビュードラグアンドドロップ
    void RightView_DragEnter(object? s, DragEventArgs e)
    {
        e.Effect = DragDropEffects.All;
    }
    async void RightView_DragDrop(object? s, DragEventArgs e)
    {
        if (e.Data == null) return;
        Object? obj = e.Data.GetData(DataFormats.FileDrop, false);
        if (obj == null) return;
        var path = ((string[])obj)[0];

        using var fs = new FileStream(path, FileMode.Open, FileAccess.Read);
        rightBitmap?.Dispose();
        rightBitmap = await Task.Run(()=>(Bitmap)Bitmap.FromStream(fs));
        rightMatrix = new Matrix();
        leftMatrix?.Reset();
        DrawImage();

    }
    // ビットマップの描画
    void DrawImage()
    {
        if (rightBitmap is not null && rightGraphics is not null) {
            if (rightMatrix is not null)
                rightGraphics.Transform = rightMatrix;
            
            rightGraphics.Clear(rightView.BackColor);
            rightGraphics.DrawImage(rightBitmap, 0, 0, rightBitmap.Width, rightBitmap.Height);
            rightView.Refresh();
        }
        if (leftBitmap is not null && leftGraphics is not null) {
            if (leftMatrix is not null)
                leftGraphics.Transform = leftMatrix;
            
            leftGraphics.Clear(leftView.BackColor);
            leftGraphics.DrawImage(leftBitmap, 0, 0, leftBitmap.Width, leftBitmap.Height);
            leftView.Refresh();
        }
    }
    // マウスダウンイベント
    void View_MouseDown(object? sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Right) {
            rightMatrix?.Reset();
            leftMatrix?.Reset();
            DrawImage();
            return;
        }

        if (rightBitmap is not null) {

            rightView.Focus();
            
            rightMousePostion.X = e.X;
            rightMousePostion.Y = e.Y;

            rightIsMouseMoving = true;
        }
        if (leftBitmap is not null) {
            leftView.Focus();
            
            leftMousePostion.X = e.X;
            leftMousePostion.Y = e.Y;

            leftIsMouseMoving = true;
        }
    }
    // マウス移動イベント
    void View_MouseMove(object? sender, MouseEventArgs e)
    {
        bool flag = false;
        if (rightBitmap is not null && rightMatrix is not null) {
            if (rightIsMouseMoving == true) {
                float xx = e.X - rightMousePostion.X;
                float yy = e.Y - rightMousePostion.Y;

                rightMatrix.Translate(xx, yy, MatrixOrder.Append);
                flag = true;
                rightMousePostion.X = e.X;
                rightMousePostion.Y = e.Y;
            }
        }
        if (leftBitmap is not null && leftMatrix is not null) {
            if (leftIsMouseMoving == true) {
                float xx = e.X - leftMousePostion.X;
                float yy = e.Y - leftMousePostion.Y;

                leftMatrix.Translate(xx, yy, MatrixOrder.Append);
                flag = true;
                leftMousePostion.X = e.X;
                leftMousePostion.Y = e.Y;
            }
        }
        if (flag)
            DrawImage();
    }
    // マウスアップイベント
    void View_MouseUp(object? sender, MouseEventArgs e)
    {
        if (rightBitmap is not null)
            rightIsMouseMoving = false;
        if (leftBitmap is not null)
            leftIsMouseMoving = false;
    }
    // マウスホイールイベント
    void View_MouseWheel(object? sender, MouseEventArgs e)
    {
        bool flag = false;
        if (rightBitmap is not null && rightMatrix is not null) {
            rightMatrix.Translate(-e.X, -e.Y, MatrixOrder.Append);

            if (e.Delta > 0) {
                if (rightMatrix.Elements[0] < 100) {
                    rightMatrix.Scale(1.5f, 1.5f, MatrixOrder.Append);
                }
            } else {
                if (rightMatrix.Elements[0] > 0.01) {
                    rightMatrix.Scale(1.0f/1.5f, 1.0f/1.5f, MatrixOrder.Append);
                }
            }

            rightMatrix.Translate(e.X, e.Y, MatrixOrder.Append);
            flag = true;
        }
        if (leftBitmap is not null && leftMatrix is not null) {
            leftMatrix.Translate(-e.X, -e.Y, MatrixOrder.Append);

            if (e.Delta > 0) {
                if (leftMatrix.Elements[0] < 100) {
                    leftMatrix.Scale(1.5f, 1.5f, MatrixOrder.Append);
                }
            } else {
                if (leftMatrix.Elements[0] > 0.01) {
                    leftMatrix.Scale(1.0f/1.5f, 1.0f/1.5f, MatrixOrder.Append);
                }
            }

            leftMatrix.Translate(e.X, e.Y, MatrixOrder.Append);
            flag = true;
        }

        if (flag)
            DrawImage();
    }
}

ビルド

dotnet build -c Release

機能

  • フォームの左右に各々画像をファイルをエクスプローラーなどからドラッグアンドドロップで画像が表示
  • マウスのホイールで画像の拡大縮小
  • マウスのドラッグで画像が移動

説明

前回のコードでは拡大縮小するピクチャボックスベースのユーザーコントロールを作成しましたが、マウスイベントを2つのコントロールで連動させる方法が思いつかなかったので、シンプルに2つのピクチャボックス並べる方法にしてみました。

コメント