简体   繁体   English

填充矩形的 WndProc 中未收到 WM_LBUTTONDOWN 和 WM_LBUTTONUP 消息

[英]WM_LBUTTONDOWN and WM_LBUTTONUP messages are not received in the WndProc for filled rectangles

I have made a semi-transparent, borderless form with a resizable transparent panel in the middle.我制作了一个半透明、无边框的表格,中间有一个可调整大小的透明面板。 To do this, overriding the OnPaint , I painted dashed borders and boxes around the panel using e.Graphics.DrawLines(...) , e.Graphics.FillRectangles(...) , and e.Graphics.DrawRectangles(...) methods.为此,我覆盖了OnPaint ,使用e.Graphics.DrawLines(...)e.Graphics.FillRectangles(...)e.Graphics.DrawRectangles(...) ...) 在面板周围绘制了虚线边框和框。 e.Graphics.DrawRectangles(...)方法。 I then handled the WM_NCHITTEST and WM_MOUSEMOVE in the WndProc as below.然后我在WndProc中处理了WM_NCHITTESTWM_MOUSEMOVE ,如下所示。

protected override void WndProc(ref Message m)
{
    bool handled = false;

    if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE)
    {
        if (...) // any of the boxes contains the client-point
        {
            m.Result = (IntPtr)HT; // HT can be HTLEFT = 10, HTRIGHT = 11, and so on
            handled = true;
        }
    }

    if (!handled)
        base.WndProc(ref m);
}

半透明无边框窗体中间可调整大小的透明面板

So far so good—the dashed borders and the boxes filled with a white brush pass the hit test successfully.到目前为止一切顺利——虚线边框和用白色画笔填充的框成功通过了命中测试。 Now, I also need to handle the WM_LBUTTONDOWN and WM_LBUTTONUP messages in the WndProc .现在,我还需要处理WndProc中的WM_LBUTTONDOWNWM_LBUTTONUP消息。 It seems the WndProc receives either of these messages only when the poiner is over the borders of the panel (ie, drawn with the e.Graphics.DrawLines(...) ) or the borders of the boxes (ie, drawn with the e.Graphics.DrawRectangles(...) ) but not when the mouse pointer is over the filled area of the boxes (ie, filled with the e.Graphics.FilledRectangles(...) ).似乎WndProc仅在指针超出面板边界(即,使用e.Graphics.DrawLines(...)绘制)或框的边界(即,使用e.Graphics.DrawRectangles(...)绘制e.Graphics.DrawRectangles(...) )但当鼠标指针位于框的填充区域上时(即,用e.Graphics.FilledRectangles(...)填充)。 Any sggestions as why this is happening?关于为什么会发生这种情况的任何建议?

protected override void WndProc(ref Message m)
{
    bool handled = false;

    if (m.Msg == WM_LBUTTONDOWN || m.Msg == WM_LBUTTONUP)
    {
        // unreachable for the filled rectangles!?
    }

    if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE)
    {
        ...
    }

    if (!handled)
        base.WndProc(ref m);
}

Here is the whole code.这是整个代码。

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

namespace Microfluidic_Experiment_Assistant
{
    public class FloatingPanel : Panel
    {
        #region __________ Declarations

        public enum SizingModes
        {
            Normal,
            GripBoxesOnly
        }

        #endregion

        #region __________ Fields

        private RectangleF TopLeftBox;
        private RectangleF TopBox;
        private RectangleF TopRightBox;
        private RectangleF LeftBox;
        private RectangleF RightBox;
        private RectangleF BottomLeftBox;
        private RectangleF BottomBox;
        private RectangleF BottomRightBox;

        private RectangleF TopBorder;
        private RectangleF LeftBorder;
        private RectangleF RightBorder;
        private RectangleF BottomBorder;

        #endregion

        #region __________ Properties

        public SizingModes SizingMode
        {
            get;
            set;
        }

        public float BorderThickness
        {
            get;
            set;
        }
        = 1F;

        public int GripSize
        {
            get;
            set;
        } = 10;

        #endregion

        #region __________ Methods

        private void RefreshBoxesAndBorders()
        {
            TopLeftBox = new RectangleF(0, 0, GripSize, GripSize);
            TopBox = new RectangleF((this.ClientSize.Width - GripSize) / 2, 0, GripSize, GripSize);
            TopRightBox = new RectangleF(this.ClientSize.Width - GripSize - BorderThickness, 0, GripSize, GripSize);
            LeftBox = new RectangleF(0, (this.ClientSize.Height - GripSize) / 2, GripSize, GripSize);
            RightBox = new RectangleF(this.ClientSize.Width - GripSize - BorderThickness, (this.ClientSize.Height - GripSize) / 2, GripSize, GripSize);
            BottomLeftBox = new RectangleF(0, this.ClientSize.Height - GripSize - BorderThickness, GripSize, GripSize);
            BottomBox = new RectangleF((this.ClientSize.Width - GripSize) / 2, this.ClientSize.Height - GripSize - BorderThickness, GripSize, GripSize);
            BottomRightBox = new RectangleF(this.ClientSize.Width - GripSize - BorderThickness, this.ClientSize.Height - GripSize - BorderThickness, GripSize, GripSize);

            TopBorder = new Rectangle(0, 0, this.ClientSize.Width, GripSize);
            LeftBorder = new Rectangle(0, 0, GripSize, this.ClientSize.Height);
            RightBorder = new Rectangle(this.ClientSize.Width - GripSize, 0, GripSize, this.ClientSize.Height);
            BottomBorder = new Rectangle(0, this.ClientSize.Height - GripSize, this.ClientSize.Width, GripSize);
        }

        #endregion

        #region __________ Event Handler

        public FloatingPanel()
        {
            this.DoubleBuffered = true;
            this.ResizeRedraw = true;
        }

        protected override void WndProc(ref Message m)
        {
            const uint WM_NCHITTEST = 0x0084;
            const uint WM_MOUSEMOVE = 0x0200;
            const uint WM_LBUTTONDOWN = 0x0201;
            const uint WM_LBUTTONUP = 0x0202;
            const uint HTLEFT = 10;
            const uint HTRIGHT = 11;
            const uint HTBOTTOMRIGHT = 17;
            const uint HTBOTTOM = 15;
            const uint HTBOTTOMLEFT = 16;
            const uint HTTOP = 12;
            const uint HTTOPLEFT = 13;
            const uint HTTOPRIGHT = 14;


            bool handled = false;

            if (m.Msg == WM_LBUTTONDOWN || m.Msg == WM_LBUTTONUP)
            {

            }

            if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE)
            {
                Dictionary<uint, RectangleF> boxes;
                Point screenPoint = new Point(m.LParam.ToInt32());
                Point clientPoint = this.PointToClient(screenPoint);

                RefreshBoxesAndBorders();

                switch (SizingMode)
                {
                    case SizingModes.Normal:
                        boxes = new Dictionary<uint, RectangleF>()
                        {
                            { HTBOTTOMLEFT,  BottomLeftBox },
                            { HTBOTTOMRIGHT, BottomRightBox },
                            { HTTOPRIGHT,    TopRightBox },
                            { HTTOPLEFT,     TopLeftBox },
                            { HTBOTTOM,      BottomBorder },
                            { HTRIGHT,       RightBorder },
                            { HTTOP,         TopBorder },
                            { HTLEFT,        LeftBorder }
                        };
                        break;

                    case SizingModes.GripBoxesOnly:
                        boxes = new Dictionary<uint, RectangleF>()
                        {
                            { HTBOTTOMLEFT,  BottomLeftBox },
                            { HTBOTTOM,      BottomBox },
                            { HTBOTTOMRIGHT, BottomRightBox },
                            { HTRIGHT,       RightBox },
                            { HTTOPRIGHT,    TopRightBox },
                            { HTTOP,         TopBox },
                            { HTTOPLEFT,     TopLeftBox },
                            { HTLEFT,        LeftBox }
                        };
                        break;

                    default:
                        throw new NotImplementedException();
                }

                foreach (KeyValuePair<uint, RectangleF> hitBox in boxes)
                {
                    if (hitBox.Value.Contains(clientPoint))
                    {
                        m.Result = (IntPtr)hitBox.Key;
                        handled = true;

                        break;
                    }
                }
            }

            if (!handled)
                base.WndProc(ref m);
        }

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

            RefreshBoxesAndBorders();

            Pen pen = new Pen(Color.FromArgb(255, 0, 78), 2 * BorderThickness)
            {
                DashPattern = new float[] { 5, 5 }
            };

            // Draw dashed borders
            //
            e.Graphics.DrawLines(pen, new PointF[]
            {
            new PointF(BorderThickness, BorderThickness),
            new PointF(this.ClientSize.Width - BorderThickness, BorderThickness),
            new PointF(this.ClientSize.Width - BorderThickness, this.ClientSize.Height - BorderThickness),
            new PointF(BorderThickness, this.ClientSize.Height - BorderThickness),
            new PointF(BorderThickness, BorderThickness),
            });

            // Fill grip boxes
            //
            e.Graphics.FillRectangles(new SolidBrush(Color.White), new RectangleF[] { TopLeftBox, TopBox, TopRightBox, LeftBox, RightBox, BottomLeftBox, BottomBox, BottomRightBox });

            // Draw grip box borders
            //
            e.Graphics.DrawRectangles(new Pen(Color.Black, BorderThickness), new RectangleF[] { TopLeftBox, TopBox, TopRightBox, LeftBox, RightBox, BottomLeftBox, BottomBox, BottomRightBox });
        }

        #endregion
    }
}

and here is how the panel look at the design time.以下是面板如何看待设计时间。

设计时间

The main form properties (from the designer):主要表单属性(来自设计器):

this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.Gray;
this.ClientSize = new System.Drawing.Size(350, 350);
this.Controls.Add(this.ScenePanel);
this.DoubleBuffered = true;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "MainForm";
this.Opacity = 0.7D;
this.Text = "MainForm";
this.TopMost = true;
this.TransparencyKey = System.Drawing.Color.Green;
this.WindowState = System.Windows.Forms.FormWindowState.Maximized;

Wild guess;胡乱猜测; try WM_NCLBUTTONDOWN and WM_NCLBUTTONUP instead.尝试WM_NCLBUTTONDOWNWM_NCLBUTTONUP代替。

If that doesn't help, try running Spy++ to see which mouse messages are in fact sent.如果这没有帮助,请尝试运行Spy++以查看实际发送了哪些鼠标消息。 Also, handling mouse messages that do not belong to your own window (ie the Desktop ) requires a mouse hook .此外,处理属于您自己的 window(即Desktop )的鼠标消息需要鼠标钩子

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM