1

私はこれに苦労しており、正しい手順としてこれを推奨するいくつかのstackoverflowの投稿を見てきました:

クリックスルーで常に最前面に表示される透明なウィンドウ レイヤー

私のコードでは、この手法をほぼ正確に踏襲しています。それでも、私のコードは機能せず、その理由が少しわかりません。間違った手順を使用していないかどうか疑問に思っていますか? 明確にするために、私が望む効果は、ユーザーがフォームをクリックして、その下にある何かにアクセスすることです。たとえば、ビジュアルスタジオの上で実行しています。アプリをクリックしようとすると、代わりに Visual Studio をクリックします。

アップデート:

コードを呼び出すと、次の 2 つのいずれかが発生します (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% 不透明に見える) ように、 を別の値に変更する必要があります。ただしbool flag、 でスタイルが初期化されないようにするために some を使用し、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 をオーバーライドすることです。

そうすれば、スタイルは作成時から存在します。 SetWindowLong100%効果的にするには遅すぎるかもしれません。

于 2013-09-05T16:30:21.080 に答える