【问题标题】:Preventing mouse clicks through a transparent Windows Form通过透明的 Windows 窗体防止鼠标点击
【发布时间】:2013-04-07 12:31:31
【问题描述】:

我正在制作一个小工具,用于在浮动侧边栏中切换“笔”按钮后用鼠标在屏幕上绘图。

我已经做到了这一点(请不要笑),让一个最顶层的窗口窗体以其背景作为其透明度键覆盖整个屏幕。 当我处于绘图模式时,我需要让鼠标不要在表单上单击下面的内容。我尝试遵循以下操作: Windows form with a transparent background that cannot be clicked through How to disable click through on transparent control?

它成功地停止了鼠标但也取消了最大化表单并用鼠标拖动它(使用 HTCAPTION IntPtr(2) 这是)我尝试使用 MSDN 上列出的其他一些值,但没有运气。

我的深度不够,任何帮助都非常感谢(新手友好请!)

PS 我现在正在用这个..

        //code for allowing clicking through of menus
        protected override void WndProc(ref Message m)
        {              
            if (penMode && m.Msg == 0x84)
            {
                m.Result = new IntPtr(2);    
            }
            else
                base.WndProc(ref m);
        }

更新:现在通过完全以另一种方式解决问题。看起来 WndProc 不起作用,所以我只是在整个屏幕上创建了一个空白表单,并在其中显示了我的主表单 (form.Show(this))。然后将位于下方的空白表单的不透明度从 0% 调整为 1% 以允许/防止点击。作品! 感谢所有的答案,教会了我很多。

【问题讨论】:

    标签: c# winforms


    【解决方案1】:

    实际上,没必要笑——在我看来,你已经以正确的方式做这件事了。由于您不拥有桌面,因此不应直接在其上绘图。相反,您需要通过覆盖您拥有的透明表单来模拟它,然后在其上进行绘制。因为你拥有透明的覆盖表单,所以在上面画画是没有问题的。

    但除此之外,听起来您只是在随机尝试值,而没有清楚地了解它们的实际作用。这就像闭着眼睛扔飞镖一样。您的命中数不会很高。

    让我们从了解您的代码的作用开始。魔术值0x84 对应于WM_NCHITTEST 消息,该消息由Windows 发送到窗口以确定应如何处理该窗口上的鼠标单击。作为对该消息的响应,您使用链接文档中给出的HT* 值之一进行回复。这些值中的每一个都有特定的含义,文档中也对此进行了说明。例如:

    • HTCAPTION(其值为 2)表示窗口的单击部分应被视为窗口的标题/标题栏。您从使用 Windows 中知道,您可以使用标题栏在屏幕上拖动窗口,因此返回 HTCAPTION 以响应鼠标单击将允许您的窗口可拖动是有道理的。您会在无边界表单(即没有标题栏的表单)上看到这一点,以使它们可以移动。

    • HTTRANSPARENT(其值为 -1)是另一个可用值。这个很简单。它只是让你的窗口看起来透明。这就像在说“别介意我,这里没有窗户!”鼠标点击会简单地传递到按 Z 顺序位于您下方的窗口,就好像您不在那里一样。

    • HTCLIENT(值为 1)是当点击发生在窗口客户区的任意位置时的默认结果。当您希望一切正常工作时,您将返回它(或简单地调用默认窗口过程)。返回此值的单击事件将继续由框架正常处理,引发表单的 Click 事件,或传递给位于表单上的子控件。

    因此,当您绘图时,您可能希望返回HTTRANSPARENT。当您正在绘图时,您可能希望返回HTCLIENT,以便您的绘图代码可以看到鼠标事件并绘制结果。

    修复您的代码,然后:

    // Code for allowing clicking through of the form
    protected override void WndProc(ref Message m)
    {
        const uint WM_NCHITTEST = 0x84;
    
        const int HTTRANSPARENT = -1;
        const int HTCLIENT      = 1;
        const int HTCAPTION     = 2;
        // ... or define an enum with all the values
    
        if (m.Msg == WM_NCHITTEST)
        {
            // If it's the message we want, handle it.
            if (penMode)
            {
                // If we're drawing, we want to see mouse events like normal.
                m.Result = new IntPtr(HTCLIENT);
            }
            else
            {
                // Otherwise, we want to pass mouse events on to the desktop,
                // as if we were not even here.
                m.Result = new IntPtr(HTTRANSPARENT);
            }
            return;  // bail out because we've handled the message
        }
    
        // Otherwise, call the base class implementation for default processing.
        base.WndProc(ref m);
    }
    

    【讨论】:

    • 在windows 8机器上测试,鼠标点击时窗口的透明部分不会向父窗口发送消息。 (在记录消息和 Spy++ 中经过验证)。
    • @Cody,哇,非常感谢您提供如此清晰而完整的答案!它看起来不错,但我现在看到的是,在绘制一个点之后,如果我再次点击该点,现在是蓝色的,不透明,点击通过..
    • 不能在 Windows 10 上运行,原因与 John 提到的相同。
    • 我帮不了你,@bonner。我没有在任何地方安装 Windows 8 或 10。不是重点,我的电脑上没有连接触摸屏。
    • ChronosMOT 建议的解决方案是可行的,尽管它是一个 hacky 解决方法。
    【解决方案2】:

    您可能只想将窗口的可见性设置为 5% 左右,并停用透明键。

    你基本上不会注意到它并喷射它在那里:D

    希望对你有帮助

    【讨论】:

    • 谢谢@Chronos,但是有什么办法可以做到这一点,按钮,更重要的是,我用钢笔模式绘制的东西不是 5% 可见的?
    • 我想我低估了这个问题。我现在有一个使用三种形式的解决方案。由于透明键,第一个只是显示 gui 蜂几乎不可见。第二个仅控制输入,可见性为 5%。第三个再次使用透明度键绘制。抱歉,我之前没有想到这一点。这次测试了这里是文件以及包含所有文件的.rar drive.google.com/…
    • 谢谢,我已经使用两种形式提出了类似的解决方案 - 我使用与 UI 相同的一种,我还没有更新解决方案,因为我无法完全在所有目标机器上进行测试。很高兴看到我的想法和其他人一样!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多