1

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

透明窗口层,可点击并始终位于顶部

在我的代码中,我几乎完全遵循这种技术。然而,我的代码不起作用,我对为什么有点困惑。我想知道我是否使用了错误的程序?需要明确的是,我想要的效果是让用户单击我的表单并访问它下面的内容。例如,我在 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();
    }
4

2 回答 2

2

我们有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;
    }
}

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

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;
    }
}
于 2013-09-05T18:05:55.970 回答
0

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

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

于 2013-09-05T16:30:21.080 回答