Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

C# 画面キャプチャ範囲をユーザーが選択するためのFORMを使ったフレーム

More than 3 years have passed since last update.

画面キャプチャ時のフレーム

デスクトップ画面のキャプチャをするときに、
ユーザーが選択範囲を選んで位置を確認するためのフレームをC#のFormにて作成

B.JPG

--- ユーザー操作 ---

  • ドラッグで移動
  • ドラッグで拡大縮小(呼び出し側で切り替え可能)

サンプルコード(呼び出し側)

using System;
using System.Drawing;
using System.Windows.Forms;
using CaptureAreaSelector;

namespace testForm
{
    public partial class Form1 : Form
    {

        FrameForm frame;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            frame = new FrameForm();

            frame.ShowInTaskbar = false; //タスクバーに表示させない

            frame.FrameBorderSize = 10; //線の太さ

            frame.FrameColor = Color.Blue; //線の色

            frame.AllowedTransform = true; //サイズ変更の可否

            frame.Show();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (frame!=null)
                MessageBox.Show(frame.SelectedWindow.ToString());
        }
    }
}

サンプルコード

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace CaptureAreaSelector
{

    public partial class FrameForm : Form
    {
        private static readonly Color PrimaryTransparencyKey = Color.White;
        private static readonly Color SecondaryTransparencyKey = Color.Black;

        /// <summary>
        /// 選択範囲の位置と範囲です。
        /// </summary>
        [Category("配置"), Description("選択範囲の位置と範囲です")]
        public Rectangle SelectedWindow
        {
            get
            {
                var rect = this.Bounds;
                rect.Inflate(_FrameBorderSize * -1, _FrameBorderSize * -1);
                return rect;
            }
        }

        private Color _FrameColor = Color.Red;
        /// <summary>
        /// フレームの色です
        /// </summary>
        [Category("表示"), Description("フレームの色です")]
        [DefaultValue(typeof(Color), "Red")]
        public Color FrameColor {
            get { return _FrameColor; }
            set
            {
                _FrameColor = value;
                if (_FrameColor == PrimaryTransparencyKey)
                    this.TransparencyKey = SecondaryTransparencyKey;
                else
                    this.TransparencyKey = PrimaryTransparencyKey;
                this.Refresh();
            }
        }

        private int _FrameBorderSize = 5;
        /// <summary>
        /// フレームの線の太さです
        /// </summary>
        [Category("表示"), Description("フレームの線の太さです")]
        [DefaultValue(5)]
        public int FrameBorderSize
        {
            get { return _FrameBorderSize; }
            set
            {
                _FrameBorderSize = value;
                this.Refresh();
            }
        }

        /// <summary>
        /// フレームの変形を許可します
        /// </summary>
        [Category("動作"), Description("フレームの変形を許可します")]
        [DefaultValue(true)]
        public bool AllowedTransform { get; set; } = true;

        Point mousePoint; //マウス位置の一時記憶

        public FrameForm()
        {
            InitializeComponent();
            FormBorderStyle = FormBorderStyle.None;
            this.TransparencyKey = PrimaryTransparencyKey;
        }

        /// <summary>
        /// 枠だけ残して透明にする
        /// </summary>
        /// <param name="g"></param>
        void draw(Graphics g)
        {
            var rct = this.ClientRectangle;
            g.FillRectangle(new SolidBrush(FrameColor), rct);
            rct.Inflate(FrameBorderSize * -1, FrameBorderSize * -1);
            g.FillRectangle(new SolidBrush(TransparencyKey), rct);            
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
            {
                //位置を記憶する
                mousePoint = new Point(e.X, e.Y);
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (AllowedTransform)
            {
                if (e.X > Width * 2 / 3 && e.Y > Height * 1 / 2) //カーソルが右下なら
                    frameTransform(e);
                else
                    frameMove(e);
            }
            else
                frameMove(e);

            base.OnMouseMove(e);
        }

        void frameMove(MouseEventArgs e)
        {
            Cursor = Cursors.SizeAll;

            if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
            {
                this.Left += e.X - mousePoint.X;
                this.Top += e.Y - mousePoint.Y;
            }
        }

        void frameTransform(MouseEventArgs e)
        {
            if (AllowedTransform)
            {
                Cursor = Cursors.SizeNWSE;

                if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
                {

                    this.Width += e.X - mousePoint.X;
                    mousePoint.X += e.X - mousePoint.X;

                    this.Height += e.Y - mousePoint.Y;
                    mousePoint.Y += e.Y - mousePoint.Y;
                }
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            draw(e.Graphics);
            base.OnPaint(e);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            this.Refresh();
        }
    }
}

※呼び出し側と呼び出され側で別プロジェクトになっています

課題

1.サイズを拡大するときに残像が残る
 →解決しました、o2kazuma様ありがとうございます。
2.サイズ変更可否の切り替えに無理やり感
 →サイズ変更可否のプロパティは派生クラスに乗せて、OnMouseMoveメソッドをオーバーライドした方がよい??
3.ドラッグで移動させるためのMouseイベントがいくつか並んでいるが、どうもすっきりしない(Controlに対してたまに使う機能群なので)
 →すっきり一まとめにする良い方法はないものか

作ってみて

このフレームは、キャプチャのための枠取りとして何となく作ったが、他にもいろいろと応用が利きそう。呼び出し側FormのPictureBoxに投影させてみたり。
そこまで考えると、実はcontrolクラスから継承させたほうがよい?わからん。
とりあえず、コントロールを作るのは楽しい。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away