0

フォームに小さなパネルのフィールドを作成しましたが、ユーザーがこれらのパネルに色を付けられるようにしたいと考えています。それらに色を付けるには、パネルをクリックするだけです。これは機能します。ここで、ユーザーがパネルをクリックして他のパネルにドラッグして、一度に複数のパネルに色を付けられるようにしたいと考えています。

ブール値を設定するために、すべてのパネルに mousedown および mouseup イベントを追加しました。パネルに色を付けるには、mousemove イベントを使用します。それでも、最初のパネルだけが着色されます。

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

namespace Application
{
    public partial class Form1 : Form
    {
        private const int dim = 25;
        private int cols;
        private int rows;

        private bool mouse_down = false;
        private sbyte fill = -1;
        private Panel pnlTmp;

        public Form1()
        {
            InitializeComponent();

            this.buildGrid();
        }


        /// <summary>
        /// Rebuild the grid to fit the screen.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolStripMenuItem2_Click(object sender, EventArgs e)
        {
            this.buildGrid();
        }


        /// <summary>
        /// Build the grid to fit the screen.
        /// </summary>
        private void buildGrid()
        {
            panel1.Controls.Clear();

            cols = int.Parse(Math.Floor((double)panel1.Width / dim).ToString());
            rows = int.Parse(Math.Floor((double)panel1.Height / dim).ToString());

            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    Panel pnl = new Panel();
                    pnl.BorderStyle = BorderStyle.FixedSingle;
                    pnl.Width = dim;
                    pnl.Height = dim;
                    pnl.Location = new Point(j * 25 + 1, i * 25 + 1);
                    pnl.Name = string.Format("pnl-{0}-{1}", j, i);
                    pnl.MouseDown += new MouseEventHandler(pnl_MouseDown);
                    pnl.MouseUp += new MouseEventHandler(pnl_MouseUp);
                    pnl.MouseMove += new MouseEventHandler(pnl_MouseHover);
                    panel1.Controls.Add(pnl);
                }
            }
        }

        void pnl_MouseHover(object sender, EventArgs e)
        {
            if (mouse_down)
            {
                Panel p = (Panel)sender;
                if (p != pnlTmp)
                {
                    if (fill == -1)
                        fill = (p.BackColor == SystemColors.Control) ? (sbyte)1 : (sbyte)0;

                    if (fill == 1)
                        p.BackColor = Color.Blue;
                    else
                        p.BackColor = SystemColors.Control;

                    Debug.WriteLine(p.Name);
                }

                pnlTmp = p;
            }
        }

        void pnl_MouseDown(object sender, MouseEventArgs e)
        {
            Debug.WriteLine("true");
            mouse_down = true;
        }

        void pnl_MouseUp(object sender, MouseEventArgs e)
        {
            Debug.WriteLine("false");
            mouse_down = false;
            fill = -1;
        }

        private void panel1_MouseLeave(object sender, EventArgs e)
        {
            //mouse_down = false;
            //fill = -1;
        }
    }
}

アプリケーションのデバッグを試みたところ、他のパネルに移動していても、最初のパネルだけがイベントを発生し続けるという結果になりました。

誰かがこれがなぜなのか教えてもらえますか?

4

1 に答える 1

2

あなたの問題は、「マウス キャプチャ」と呼ばれる機能が原因です。Control.Capture プロパティによって制御されます。デフォルトの動作では、MouseDown イベントが発生する前に、OnMouseDown() メソッドで自動的にオンになります。

マウス キャプチャは、マウスをウィンドウの外に移動した場合でも、すべてのマウス イベントがクリックしたウィンドウに向けられるように強制します。これが、クリックしたパネルの MouseMove および MouseUp イベントのみを取得する理由です。多くのシナリオで、特に Click および MouseUp イベントを確実に生成することが重要です。

回避策は、MouseDown イベント ハンドラでキャプチャをオフに戻すことです。

    void pnl_MouseDown(object sender, MouseEventArgs e) {
        ((Control)sender).Capture = false;
    }

新しい問題が発生したことに注意してください。「mouse_down」変数は信頼できなくなりました。マウスをパネルの外またはフォームの外に移動してマウスを離すと、MouseUp イベントが間違ったウィンドウに送信され、マウスが押されていなくても、mouse_down 変数が true に設定されたままになります。キャプチャ機能によって提供される保証を失いました。次のように、MouseMove イベント ハンドラーでボタンの状態を確認することで、この問題を解決します。

    private void pnl_MouseMove(object sender, MouseEventArgs e) {
        if (e.Button == MouseButtons.Left) {
            // etc...
        }
    }

誤った pnl_MouseHover イベント ハンドラを修正し、名前を pnl_MouseMove に変更したことに注意してください。どうやってこの間違いを犯してしまったのかはわかりますが、それが原因でこの解決策を自分で発見できなかった可能性があります。ユージーンの斧には気をつけて ;)

于 2012-12-27T13:16:55.153 に答える