首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >点击是不起作用的- SetWindowLong是正确的技术吗?

点击是不起作用的- SetWindowLong是正确的技术吗?
EN

Stack Overflow用户
提问于 2013-09-05 15:20:23
回答 2查看 1.4K关注 0票数 1

我一直在努力解决这一问题,并查看了几个堆栈溢出帖子,这些帖子建议将此作为正确的过程:

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

在我的代码中,我几乎完全遵循这个技术。然而,我的代码不起作用,我有点困惑于为什么。我在想我是不是用错了?为了清楚起见,我想要的效果是用户单击我的表单并访问它下面的内容。例如,我正在visual之上运行。如果我尝试单击该应用程序,则单击visual。

更新:

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

  1. 窗口不作画
  2. 该窗口可绘制,但可单击。

选项1发生在我在initializecomponent选项2之后运行代码时,当我在initializecomponent之前运行它时。

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

代码语言:javascript
复制
    [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();
    }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-09-05 18:05:55

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

代码语言:javascript
复制
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;
    }
}

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

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2013-09-05 16:30:21

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

这样,风格就会从创造中呈现出来。SetWindowLong可能将其设置得太晚,无法达到100%的效果。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18640196

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档