【问题标题】:click-through is not working - is SetWindowLong the proper technique?点击不起作用 - SetWindowLong 是正确的技术吗?
【发布时间】:2013-09-06 02:05:55
【问题描述】:

我一直在为此苦苦挣扎,并查看了几篇推荐此作为正确程序的 stackoverflow 帖子:

Transparent window layer that is click-through and always stays on top

在我的代码中,我几乎完全遵循这种技术。然而,我的代码不起作用,我对为什么有点困惑。我想知道我是否使用了错误的程序?需要明确的是,我想要的效果是让用户单击我的表单并访问它下面的内容。例如,我在 Visual Studio 之上运行。如果我尝试点击该应用程序,我会改为点击 Visual Studio。

更新:

当我调用我的代码时,会发生以下两种情况之一(取决于我调用 setwindowlong 方法的位置):

  1. 窗口不绘制
  2. 窗口已绘制,但可点击

选项 1 发生在我在 initializecomponent 之后立即运行代码时 选项 2 在我在 initializecomponent 之前运行时发生

这是在其他任何事情之前绘制我的表单的完整代码:

    [DllImport("user32.dll", SetLastError = true)]
    static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

    [DllImport("user32.dll")]
    static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);

    public frmPhoneQueueViewer()
    {
        InitializeComponent();
        // Set the form click-through
        int initialStyle = GetWindowLong(this.Handle, -20);
        SetWindowLong(this.Handle, -20, initialStyle | 0x80000 | 0x20);


        //Get height of taskbar to exclude it, then bind to lower right of screen
        int nTaskBarHeight = Screen.PrimaryScreen.Bounds.Bottom -Screen.PrimaryScreen.WorkingArea.Bottom;
        Rectangle workingArea = Screen.GetWorkingArea(this);
        this.Location = new Point(Screen.PrimaryScreen.Bounds.Right - this.Size.Width, workingArea.Bottom - Size.Height + nTaskBarHeight);
        this.TopMost = true;

        this.FormBorderStyle = FormBorderStyle.None;
        this.ControlBox = false;
        this.Text = string.Empty;
        this.ShowInTaskbar = false;


        PopulatePhoneQueueData();
    }

【问题讨论】:

  • 与问题无关,只是想知道如果用户的任务栏位于左侧/右侧/顶部而不是底部会发生什么?
  • 怎么不工作?你应该描述细节。
  • 检查Handle 是否已经创建。如果我没记错的话,窗体的构造函数中还没有创建窗口句柄。
  • 来自文档:“CreateControl 方法强制为控件及其子控件创建句柄。当您需要立即使用句柄来操作控件或其子控件时使用此方法;只需调用控件的构造函数不会创建句柄。如果控件的 Visible 属性为 false,则 CreateControl 不会创建控件句柄。您可以调用 CreateHandle 方法或访问 Handle 属性来创建控件的句柄,而不管控件的可见性如何,但在在这种情况下,不会为控件的子级创建窗口句柄。"
  • 另外,来自 Handle 属性文档:“Handle 属性的值是 Windows HWND。如果尚未创建句柄,则引用此属性将强制创建句柄。”

标签: c# winforms


【解决方案1】:

我们有WS_EX_TRANSPARENT = 0x20,这将使您的表单完全透明。此扩展样式是创建click through window 所必需的。所以我们会有一些方法来正常显示你的窗口(否则它是透明的,这就是你认为它没有被绘制的原因),我们通过使用 win32 api 函数SetLayeredWindowAttributes 来做到这一点(如在您的代码)或简单地设置表单的 Opacity 属性。顺便说一句,您应该重写CreateParams 来初始化扩展样式,而无需声明和使用GetWindowLongSetWindowLong 方法。这是应该可以工作的代码(至少可以解决您的问题:没有绘制窗口):

public frmPhoneQueueViewer()
{
    InitializeComponent();
    //The default Opacity = 1 won't show your form
    Opacity = 0.2f; //or even Opacity = 0.999 if you like
    //....
    //....
}
protected override CreateParams CreateParams {
    get {
         CreateParams cp = base.CreateParams;
         //WS_EX_LAYERED = 0x80000  WS_EX_TRANSPARENT = 0x20
         cp.ExStyle |= 0x80000 | 0x20;                
         return cp;
    }
}

注意:我在这里发现了一件有趣的事情。如果您像上面的代码一样覆盖CreateParamsOpacity=1 将不会显示您的表单(完全透明),您必须将Opacity 更改为另一个值,例如0.2 以使其部分透明,即使@ 987654333@ 将显示您的表单(看起来像 100% 不透明度)。但是,如果您使用一些bool flag 来阻止初始化CreateParams 中的样式并稍后使用UpdateStyles() 应用样式,您的表单将在Opacity=1 时显示OK,代码如下所示:

public frmPhoneQueueViewer()
{
    InitializeComponent();
    //The default Opacity = 1 will show your form normally
    Load += (s,e) => {
        appliedStyles = true;
        UpdateStyles();//Call this to apply the styles to make your window able to click through.
    };
    //....
    //....
}
bool appliedStyles;
protected override CreateParams CreateParams {
    get {
         CreateParams cp = base.CreateParams;
         //WS_EX_LAYERED = 0x80000  WS_EX_TRANSPARENT = 0x20
         if(appliedStyles) cp.ExStyle |= 0x80000 | 0x20;                
         return cp;
    }
}

【讨论】:

    【解决方案2】:

    设置其他窗口样式的正确方法是覆盖CreateParams getter。

    这样样式将在创建时呈现。 SetWindowLong 可能会为时已晚,无法 100% 有效。

    【讨论】:

      猜你喜欢
      • 2018-03-14
      • 2023-03-14
      • 2013-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-26
      • 1970-01-01
      相关资源
      最近更新 更多