簡體   English   中英

在其他一切背后展示一張表格,而不是偷不懂焦點?

[英]Show a Form behind everything else, and without stealing focus?

StackOverflow上存在一個關於如何在不竊取焦點的情況下顯示表單的問題。 答案是覆蓋ShowWithoutActivation並返回true:

protected override bool ShowWithoutActivation
{
  get { return true; }
}

這很好用。

現在我想更進一步。 我希望展示一個表格(即使其可見),但讓它在z順序中的其他表格后面

可能在.net?

如果沒有,可以使用P / Invoke嗎?

獎金Chatter

調用SendToBack()不起作用:

   RunnerForm frm = new RunnerForm();
// frm.Show();
   frm.Visible = true;
   frm.SendToBack();

使用SetWindowPos函數的一點點PInvoke

public static class HWND {
  public static readonly IntPtr
  NOTOPMOST = new IntPtr(-2),
  BROADCAST = new IntPtr(0xffff),
  TOPMOST = new IntPtr(-1),
  TOP = new IntPtr(0),
  BOTTOM = new IntPtr(1);
}

public static class SWP {
  public static readonly int
  NOSIZE = 0x0001,
  NOMOVE = 0x0002,
  NOZORDER = 0x0004,
  NOREDRAW = 0x0008,
  NOACTIVATE = 0x0010,
  DRAWFRAME = 0x0020,
  FRAMECHANGED = 0x0020,
  SHOWWINDOW = 0x0040,
  HIDEWINDOW = 0x0080,
  NOCOPYBITS = 0x0100,
  NOOWNERZORDER = 0x0200,
  NOREPOSITION = 0x0200,
  NOSENDCHANGING = 0x0400,
  DEFERERASE = 0x2000,
  ASYNCWINDOWPOS = 0x4000;
}

[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);

private void button1_Click(object sender, EventArgs e) {
  RunnerForm frm = new RunnerForm();
  SetWindowPos(frm.Handle, HWND.BOTTOM, 0, 0, 0, 0, SWP.SHOWWINDOW | SWP.NOMOVE | SWP.NOOWNERZORDER | SWP.NOSIZE | SWP.NOACTIVATE);
}

這應該做的伎倆:

RunnerForm frm = new RunnerForm();
myMainForm.Owner = frm;

要添加Lars提供的可行解決方案 ,您還可以防止用戶完全更改窗口的Z順序。

為此,您將覆蓋窗體的WndProc方法,並捕獲在其大小,位置或Z順序位置即將更改時發送到窗口的WM_WINDOWPOSCHANGING消息 關於這條消息的超級酷的東西 - 我認為這是我的最愛之一 - 它實際上允許你改變或修改即將發生的變化的參數。

因此,在這種情況下,您需要設置SWP_NOZORDER標志以防止更改窗口的Z順序。

這種方法值得注意的是它始終會在您離開它的最后位置以Z順序維護您的窗口。 用戶將無法將其帶到前面,這可能是也可能不是好事,具體取決於UI的設計方式。 除了表單之外的控件也可以正常工作。

從我的一個庫中提取示例代碼:

internal class NativeMethods
{
    public const int WM_WINDOWPOSCHANGING = 0x46;
    public const int WM_WINDOWPOSCHANGED = 0x47;

    [Flags()]
    public enum SetWindowPosFlags
    {
        SWP_NOSIZE = 0x1,
        SWP_NOMOVE = 0x2,
        SWP_NOZORDER = 0x4,
        SWP_NOREDRAW = 0x8,
        SWP_NOACTIVATE = 0x10,
        SWP_FRAMECHANGED = 0x20,
        SWP_DRAWFRAME = SWP_FRAMECHANGED,
        SWP_SHOWWINDOW = 0x40,
        SWP_HIDEWINDOW = 0x80,
        SWP_NOCOPYBITS = 0x100,
        SWP_NOOWNERZORDER = 0x200,
        SWP_NOREPOSITION = SWP_NOOWNERZORDER,
        SWP_NOSENDCHANGING = 0x400,
        SWP_DEFERERASE = 0x2000,
        SWP_ASYNCWINDOWPOS = 0x4000,
    }

    public enum WindowZOrder
    {
        HWND_TOP = 0,
        HWND_BOTTOM = 1,
        HWND_TOPMOST = -1,
        HWND_NOTOPMOST = -2,
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct WINDOWPOS
    {
        public IntPtr hWnd;
        public IntPtr hwndInsertAfter;
        public int x;
        public int y;
        public int cx;
        public int cy;
        public SetWindowPosFlags flags;

        // Returns the WINDOWPOS structure pointed to by the lParam parameter
        // of a WM_WINDOWPOSCHANGING or WM_WINDOWPOSCHANGED message.
        public static WINDOWPOS FromMessage(Message msg)
        {
            // Marshal the lParam parameter to an WINDOWPOS structure,
            // and return the new structure
            return (WINDOWPOS)Marshal.PtrToStructure(msg.LParam, typeof(WINDOWPOS));
        }

        // Replaces the original WINDOWPOS structure pointed to by the lParam
        // parameter of a WM_WINDOWPOSCHANGING or WM_WINDOWPSCHANGING message
        // with this one, so that the native window will be able to see any
        // changes that we have made to its values.
        public void UpdateMessage(Message msg)
        {
            // Marshal this updated structure back to lParam so the native
            // window can respond to our changes.
            // The old structure that it points to should be deleted, too.
            Marshal.StructureToPtr(this, msg.LParam, true);
        }
    }
}

然后我有一個光滑的小子類形式,它引發對應於這些消息的.NET事件,並允許事件處理程序修改值或取消事件(如果需要)。 我不處理SWP_NOZORDER ,但你可以知道它是如何工作的。

public class FormEx : System.Windows.Forms.Form
{
    // ...snip constructors and such          

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case NativeMethods.WM_WINDOWPOSCHANGING:
                this.WmWindowPosChanging(m);
                return;
            // ...snip
        }

        base.WndProc(m);
    }

    private void WmWindowPosChanging(ref Message m)
    {
        // Extract the WINDOWPOS structure corresponding to this message
        NativeMethods.WINDOWPOS wndPos = NativeMethods.WINDOWPOS.FromMessage(m);

        // Determine if the size is changing (absence of SWP_NOSIZE flag)
        if (!((wndPos.flags & NativeMethods.SetWindowPosFlags.SWP_NOSIZE) == NativeMethods.SetWindowPosFlags.SWP_NOSIZE))
        {
            // Raise the LowLevelSizeChanging event
            SizeChangingEventArgs e = new SizeChangingEventArgs(this.Size, new Size(wndPos.cx, wndPos.cy));
            this.OnLowLevelSizeChanging(e);

            // Determine if the user canceled the size changing event
            if (e.Cancel)
            {
                // If so, add the SWP_NOSIZE flag
                wndPos.flags = wndPos.flags | NativeMethods.SetWindowPosFlags.SWP_NOSIZE;
                wndPos.UpdateMessage(m);
            }
        }

        // Determine if the position is changing (absence of SWP_NOMOVE flag)
        if (!((wndPos.flags & NativeMethods.SetWindowPosFlags.SWP_NOMOVE) == NativeMethods.SetWindowPosFlags.SWP_NOMOVE))
        {
            // Raise the LowLevelPositionChanging event
            PositionChangingEventArgs e = new PositionChangingEventArgs(this.Location, new Point(wndPos.x, wndPos.y));
            this.OnLowLevelPositionChanging(e);

            // Determine if the user canceled the position changing event
            if (e.Cancel)
            {
                // If so, add the SWP_NOMOVE flag
                wndPos.flags = wndPos.flags | NativeMethods.SetWindowPosFlags.SWP_NOMOVE;
                wndPos.UpdateMessage(m);
            }
        }

        base.WndProc(m);
    }

    // ...snip event infrastructure
}

編輯:嗯,這段代碼最初是用VB.NET編寫的,我是通過自動翻譯器運行的。 它似乎沒有在進行函數調用時應該在任何地方正確插入ref 按照編譯器的要求修復它...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM