質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • C#

    7121questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Visual Studio

    1834questions

    Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

  • Visual Studio 2013

    307questions

    Microsoft Visual Studio 2013は、Microsoftによる統合開発環境(IDE)であり、多種多様なプログラミング言語に対応しています。 Visual Studio 2012の次のバージョンです

visualstudioを用いたc#においての矩形の移動について

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 814
退会済みユーザー

退会済みユーザー

前提・実現したいこと

マウスで選択した箇所のみの矩形の移動

発生している問題・エラーメッセージ

マウスを矩形の上に乗せると色が変わる仕様にしたのですが
その色が変わった部分の移動方法が分かりません。

該当のソースコード

【Form.cs】

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace test20form02
{
    public partial class Form1 : Form
    {
        /// <summary>
        /// コンストラクター
        /// </summary>
        public Form1()
        {
            InitializeComponent();
            this.pen = new Pen(Color.Blue);
            this.spen = new Pen(Color.Red);
            this.recIter = new RecObjIterator();
        }

        //ペンオブジェクト
        Pen spen;
        Pen pen;

        //矩形オブジェクトのイテレータ(集合・グループ)クラス
        private RecObjIterator recIter;

        /// <summary>
        /// フォームイベントハンドラー
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            //矩形オブジェクトを100個生成する
            this.recIter.init(100);

        }

        /// <summary>
        /// ボタンクリックイベントハンドラー
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>/
        /// ピクチャーボックス ペイントイベントハンドラー
        /// 矩形を表示する
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            //矩形を表示する
            this.recIter.Draw(e.Graphics, this.spen, this.pen);
        }

        /// <summary>
        /// ピクチャーボックス マウスムーブイベントハンドラー
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            //マウス座標を取得
            var mymouse = new Point(e.X, e.Y);
            //全矩形の選択状態を解除
            this.recIter.UnSelectObj();

            //マウス座標で矩形を選択する
            this.recIter.SelectByMouse(mymouse);

            //ピクチャーボックスの再表示を依頼する
            this.pictureBox1.Invalidate();
        }


    }//class
}//namespace


【RecObj.cs】

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace test20form02
{
    /// <summary>
    /// 矩形オブジェクトの管理クラス
    /// </summary>
    class RecObj
    {
        /// <summary>
        /// プロパティ
        /// 矩形オブジェクト
        /// </summary>
        public Rectangle Rec
        {
            set { this.rec = value; }
            get { return this.rec; }

        }

        /// <summary>
        /// プロパティ
        /// 選択されているかどうか
        /// </summary>
        public bool isSelect
        {
            set { this.isselect = value; }
            get { return this.isselect; }
        }
        /// <summary>
        /// コンストラクター
        /// </summary>
        public RecObj()
        {
            this.isselect = false;
            this.rec = new Rectangle();
        }

        //選択されているかどうか
        private bool isselect;
        //矩形オブジェクト
        private Rectangle rec;

        /// <summary>
        /// 選択フラグに設定する 
        /// </summary>
        public void SetisSelect(bool flg)
        {
            this.isselect = flg;
        }

        /// <summary>
        /// オブジェクトの移動 座標の書き換え
        /// </summary>
        /// <param name="from">前のマウス座標</param>
        /// <param name="to">今のマウス座標</param>
        public void Move(Point from, Point to)
        {
            var x = to.X - from.X;
            var y = to.Y - from.Y;

            rec.X = rec.X + x;
            rec.Y = rec.Y + y;
        }

        /// <summary>
        /// 指定されたグラフィックオブジェクトに矩形を描画する
        /// </summary>
        public void Draw(Graphics gra, Pen pen, Pen pen2)
        {
            Pen mypen = null;
            if (this.isSelect)
            {
                mypen = pen;
            }
            else
            {
                mypen = pen2;
            }
            gra.DrawRectangle(mypen, this.rec);
        }
    }
}


【RecObjIterator.cs】

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace test20form02
{
    /// <summary>
    /// 矩形オブジェクトの集合を処理するクラス
    /// </summary>
    class RecObjIterator
    {
        /// <summary>
        /// プロパティ
        /// 矩形オブジェクトリストを参照
        /// </summary>
        public List<RecObj> Recs
        { 
            get { return this.recs; }
        }

        /// <summary>
        /// コンストラクター
        /// </summary>
        public RecObjIterator()
        {
            this.recs = new List<RecObj>();
        }

        //矩形オブジェクトのグループ
        private List<RecObj> recs;


        /// <summary>
        /// 矩形オブジェクトを生成する
        /// </summary>
        /// <param name="num"></param>
        public void init(int num)
        {
            for (int i = 0; i < num; i++)
            {
                var myrec = new RecObj();
                myrec.Rec = new Rectangle(10 + (i * 2), 10 + (i * 2), 100, 100);
                this.recs.Add(myrec);
            }
        }

        /// <summary>
        /// 矩形オブジェクトを追加する
        /// </summary>
        /// <param name="rec"></param>
        public void Add(RecObj rec)
        {
            this.recs.Add(rec);
        }

        /// <summary>
        /// 矩形オブジェクトのリストの選択状態を解除
        /// </summary>
        public void UnSelectObj()
        {
            foreach (var myobj in this.recs)
            {
                myobj.isSelect = false;
            }
        }

        /// <summary>
        /// マウス座標で矩形オブジェクトのリストを選択
        /// </summary>
        /// <param name="mouse"></param>
        public void SelectByMouse(Point mouse)
        {
            foreach (var myobj in this.recs)
            {
                if (myobj.Rec.Contains(mouse) == true)
                {
                    myobj.isSelect = true;
                }
            }

        }

        /// <summary>
        /// 指定されたグラフィック(キャンバス)に指定のペンで矩形を表示する
        /// </summary>
        /// <param name="gra"></param>
        /// <param name="pen"></param>
        /// <param name="pen2"></param>
        public void Draw(Graphics gra, Pen pen, Pen pen2)
        {
            foreach (var myobj in this.recs)
            {
                myobj.Draw(gra, pen, pen2);
            }
        }
    }
}

補足情報(言語/FW/ツール等のバージョンなど)

visualstudio2013

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    退会済みユーザー

    2017/04/12 14:32

    zuishinさん そうなのですが、Moveの実装がなかなかうまくいかず困っている状態です。。

    キャンセル

  • Zuishin

    2017/04/12 14:57

    マウスダウンされた時点で、矩形とカーソル位置の座標を求めます。マウスが動いた時点でその位置関係が等しくなるように動かせばいいんじゃないですか? 仮に矩形の左上が (100, 100) マウスが (110, 110) だったとすると、 マウスが (200, 200) に動いたときに矩形を (190, 190) に動かせばいいと思います。

    キャンセル

  • Zuishin

    2017/04/13 09:01

    えっ? 退会? 質問しておいて、完成品のコード貼ってもらえなかったら退会?

    キャンセル

回答 1

+1

namespaceにtest20と書いてあるのでヒント形式で回答していきたいと思います。

色が変わった部分の移動方法が分かりません。

というのでは移動の開始方法が分からないので、前提としてマウスをクリックしてる間移動するという想定でお話します。


①RecObjIteratorにMoveを実装する
複数選択できるわけですから、纏めて移動できるように拡張しましょう。

以下のようなメソッドを追加してください。

void MoveSelected(Point from, Point to)
{
    // 選択されている矩形のMoveを呼び出す
}

②矩形の移動開始地点を取得する
矩形がどこから移動を始めたのか記憶しなければいけません。
マウスがクリックされた時から移動が始まるならクリック位置が始点になります。

マウスのクリックが開始されたのを知るにはOnMouseDownイベントを使います。
マウスの移動の検知にはOnMouseMoveイベントを使います。
マウスのクリックが終了したのを知るにはOnMouseUpイベントを使います。

フォームにマウスの座標を記憶するための変数を追加してください。

以下ができていれば良いですね。

OnMouseDown
 ->MouseEventArgsから最初の座標を得る
   矩形を移動する状態にする
OnMouseMove
 ->矩形を移動する状態なら、MouseEventArgsから現在の座標を得る
   1回前の座標と組み合わせて矩形を移動する(※RecObjIterator.MoveSelectedを使う)
   現在の座標を記憶する
OnMouseUp
 ->MouseEventArgsから現在の座標を得る
   1回前の座標と異なれば、矩形を移動する(※必要ならRecObjIterator.MoveSelectedを使う)
   矩形を移動する状態を終了する

※余談ですが、マウス移動時になめらかに矩形を移動させるにはPictureBoxコントロールのCaptureプロパティをtrueにします。OnMouseDownでtrueにし、OnMouseUpでfalseにすると良いのですが、これがどういう意味かは自分で調べてみてください。


③選択された矩形を維持する
今のままだとMouseMoveが呼ばれるたびに選択される図形が変わってしまいますね。
座標の移動時にもMouseMoveイベントを経由する必要があります。
マウスがクリックされている間は同じ図形を全て移動したいのですよね。
であれば、クリックされている間は今の処理が再度呼び出されないようにする必要があります。

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    if (/* 矩形が移動中なら */)
    {
        // ここに移動用の処理を書く

        // 過去の処理で選択状態が作られているわけだから
        // 選択された矩形のMoveを呼び出せばよい
    }
    else {
        // 今までの処理...
        //マウス座標を取得
        var mymouse = new Point(e.X, e.Y);
        //全矩形の選択状態を解除
        this.recIter.UnSelectObj();

        //マウス座標で矩形を選択する
        this.recIter.SelectByMouse(mymouse);

        //ピクチャーボックスの再表示を依頼する
        this.pictureBox1.Invalidate();
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 受付中

    unityのドラッグについて

    初心者です Unityのスクリプトでオブジェクトをドラックさせて移動させたいと思い、他サイトを参考にしましたが出来ていないようでした(ドラックしようとしてもSceneがいつものよ

  • 受付中

    VB.NETでA画面からB画面を表示しB画面からさらにもう1つのインスタンスを作ってA画面を表示させ...

    前提・実現したいこと VB.NETでA画面からB画面を表示しB画面からさらにもう1つのインスタンスを作ってA画面を表示させるにはどうすればよいのでしょうか? A画面(001

  • 解決済

    C#

    C#について解決いたしました。本当に助かりました。またどうぞ宜しくお願いいたします。

  • 受付中

    カスタムエディタのフィールド。

    前提・実現したいこと ※既存のクラスにInspector拡張処理を追記する方法で、カスタムエディタを作成したいと考えています。 (EditorフォルダにInspector拡張用

  • 解決済

    ツリービューで選択した項目を通知したい(WPF)

    こんにちは。WPFを勉強中の者です。 プログラミング自体あまり明るくないため、具体的な改善点まで教えていただけると嬉しいです。 前提・実現したいこと TreeView上で

  • 解決済

    ElementHost上にPictureBoxを重ねて透過させたい

    ElementHost上にPictureBoxを重ねてPictureBoxを透過させる Windows Form Applicationにおいて、ElementHostにPict

  • 解決済

    C# CoincheckのAPIを実行したい。

    お世話になります。 C#の勉強をしたいと思い 下記のサイトより https://kokenji.net/coincheck-api/ コードを拝借してAPIを実行してみまし

  • 解決済

    ContextMenuのハイライト非表示

    前提・実現したいこと こんにちは WPFでボタン押すとContextMenuの中にカレンダーが表示され、 年月を選択できる物を作っています。 カレンダー選択まではう

同じタグがついた質問を見る

  • C#

    7121questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Visual Studio

    1834questions

    Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

  • Visual Studio 2013

    307questions

    Microsoft Visual Studio 2013は、Microsoftによる統合開発環境(IDE)であり、多種多様なプログラミング言語に対応しています。 Visual Studio 2012の次のバージョンです