简体   繁体   English

在窗体区域外绘图时如何重绘

[英]How to Repaint When Drawing Outside the Form Area

I am writing an application that needs to draw outside of it's main window area. 我正在编写一个需要在主窗口区域之外绘制的应用程序。 I already have to code to actually do the drawing: 我已经必须编写代码才能实际绘制图形:

[DllImport("User32.dll")]
public static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("User32.dll")]
public static extern void ReleaseDC(IntPtr hwnd, IntPtr dc);

IntPtr desktopPtr = GetDC(IntPtr.Zero);
Graphics g = Graphics.FromHdc(desktopPtr);

g.DrawLine(Pens.White, 0, 0, Screen.FromControl(this).WorkingArea.Width, Screen.FromControl(this).WorkingArea.Height);

g.Dispose();
ReleaseDC(IntPtr.Zero, desktopPtr);

However the on paint event is an unsuitable place to put the code because it's not called when something outside of the form is redrawn. 但是,on paint事件是放置代码的不合适位置,因为重绘表单之外的内容时不会调用它。 So my question is, where could this code be placed so it is called whenever part of the screen is redrawn? 所以我的问题是,该代码可以放在哪里,以便每当重绘屏幕的一部分时都可以调用它?

If you want content painted on the screen, you should always create a window to hold that content. 如果要在屏幕上绘制内容,则应始终创建一个窗口来保存该内容。 Painting on the desktop (a window that you don't own) is a bad idea. 在桌面(您不拥有的窗口)上绘画是一个坏主意。

The solution is to create a window, with the extended style WS_EX_NOACTIVATE and draw on that in response to WM_PAINT messages. 解决方案是创建一个具有扩展样式WS_EX_NOACTIVATE的窗口,并在其上绘制以响应WM_PAINT消息。 For a WinForms application, the runtime calls Form.OnPaint when you get a WM_PAINT so you can handle that event and do the painting there. 对于WinForms应用程序,运行时在获取WM_PAINT时将调用Form.OnPaint ,以便您可以处理该事件并在那里进行绘画。 To demonstrate: 展示:

[DllImport("User32.dll")]
private static extern IntPtr GetWindowLong(IntPtr hWnd, int index);
[DllImport("User32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int index, IntPtr value);
[DllImport("User32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

static readonly IntPtr HWND_BOTTOM = new IntPtr(1);

private const int WS_EX_NOACTIVATE = 0x08000000;
private const int GWL_EXSTYLE = -20;

private const uint SWP_NOMOVE = 0x0002;
private const uint SWP_NOSIZE = 0x0001;
private const uint SWP_NOZORDER = 0x0004;
private const uint SWP_FRAMECHANGED = 0x0020;
private const uint StyleUpdateFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED;

public Form1()
{
    InitializeComponent();
    this.FormBorderStyle = FormBorderStyle.None;
    this.Paint += Form1_Paint;
    this.Shown += Form1_Shown;
}

private void Form1_Shown(object sender, EventArgs e)
{
    IntPtr currentStyle = GetWindowLong(this.Handle, GWL_EXSTYLE);
    int current = currentStyle.ToInt32();
    current |= WS_EX_NOACTIVATE;
    SetWindowLong(this.Handle, GWL_EXSTYLE, new IntPtr(current));
    SetWindowPos(this.Handle, IntPtr.Zero, 0, 0, 0, 0, StyleUpdateFlags);
}

private void Form1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.Clear(Color.Black);
}

If you want your window to float on top set the form's TopMost property to true. 如果您希望窗口浮动在顶部,则将窗体的TopMost属性设置为true。 If you want your window to stick to the bottom of the Z-Order (the exact opposite of TopMost ) then add the following logic to your form: 如果您希望窗口TopMost在Z-Order的底部(与TopMost完全相反),则在表单中添加以下逻辑:

private struct WINDOWPOS
{
    public IntPtr hwnd;
    public IntPtr hwndInsertAfter;
    public int x;
    public int y;
    public int cx;
    public int cy;
    public uint flags;
}
private const int WM_WINDOWPOSCHANGING = 0x0046;
protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_WINDOWPOSCHANGING)
    {
        if (m.LParam != IntPtr.Zero)
        {
            WINDOWPOS posInfo = Marshal.PtrToStructure<WINDOWPOS>(m.LParam);
            posInfo.hwndInsertAfter = HWND_BOTTOM;
            Marshal.StructureToPtr(posInfo, m.LParam, true);
            m.Result = IntPtr.Zero;
            return;
        }
    }
    base.WndProc(ref m);
}

This handles the WM_WINDOWPOSCHANGING window message, and prevents the window from moving up in the Z-Order by telling the window manager to put it at the bottom. 这将处理WM_WINDOWPOSCHANGING窗口消息,并通过告诉窗口管理器将其放在底部来防止窗口在Z顺序中向上移动。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM