如何设置无边界形式的客户区(ClientRectangle)? [英] How to set the client area (ClientRectangle) in a borderless form?

查看:267
本文介绍了如何设置无边界形式的客户区(ClientRectangle)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否可以设置无边界表单的客户区。举例来说,我定义了一个如下所示的表单:

代码

  public class MyForm:Form 
{
public MyForm()
{
this.FormBorderStyle = FormBorderStyle.None;
}
}

结果





我想要做的是指定客户区域,这样窗体就有了一个框架(就像标准的windows框架,但是自定义绘制的)。

结果





基本上,蓝色区域将成为非客户区域,并且灰色区域将保持为客户区域。



我试图设置客户区域,但这似乎只是调整整个表格的大小,因此不会留下非客户端区域



这可能吗?

解决方案

这是可能的,但我不知道使用WindowStyle设置为无边界的Windows窗体。使用PInvoke(平台调用)函数,您可以删除窗口主题,它将为您提供非常基本的Windows窗体。然后,您可以使用各种PInvoke函数来操作窗体的非客户端区域。



我建议您阅读这些主题。它们是为使用C ++的Win32应用程序而设计的,但PInvoke是使用托管代码(C#)调用这些本机API的过程。



WM_NCCALCSIZE: https://msdn.microsoft.com/en-us/ library / windows / desktop / ms632634(v = vs.85).aspx

WM_NCPAINT: https://msdn.microsoft.com/en-us/library/windows/desktop/ dd145212(v = vs.85).aspx

GetDCEx: https://msdn.microsoft.com/en-us/library/windows/desktop/dd144873(v = vs。 85).aspx



GetWindowDC: https://msdn.microsoft.com/en- us / library / windows / desktop / dd144947(v = vs.85).aspx

SetWindowTheme: https://msdn.microsoft.com/zh-cn/library/windows/ desktop / bb759827(v = vs.85).aspx

这个例子非常粗略,但它提供了基本的功能。我不知道SetWindowTheme如何在Windows 8或8.1上工作,但在Windows 7中,它给了Windows经典主题。

  public partial class MyForm:Form 
{
//窗口消息
public const uint WM_NCPAINT = 0x85;
public const uint WM_NCCALCSIZE = 0x83;
public const uint WM_NCHITTEST = 0x84;

// GetDCEx标志
公共常量int DCX_WINDOW = 0x00000001;
public const int DCX_CACHE = 0x00000002;
public const int DCX_PARENTCLIP = 0x00000020;
public const int DCX_CLIPSIBLINGS = 0x00000010;
public const int DCX_CLIPCHILDREN = 0x00000008;
public const int DCX_NORESETATTRS = 0x00000004;
public const int DCX_LOCKWINDOWUPDATE = 0x00000400;
public const int DCX_EXCLUDERGN = 0x00000040;
public const int DCX_INTERSECTRGN = 0x00000080;
public const int DCX_INTERSECTUPDATE = 0x00000200;
public const int DCX_VALIDATE = 0x00200000;

// RECT结构
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct RECT
{
public int left,top,right,bottom;
}

// WINDOWPOS结构
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hwndinsertafter;
public int x,y,cx,cy;
public int flags;
}

// NCCALCSIZE_PARAMS结构
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
公共结构NCCALCSIZE_PARAMS
{
public RECT rgrc0,rgrc1,rgrc2;
public WINDOWPOS lppos;
}

// SetWindowTheme UXtheme Function
[System.Runtime.InteropServices.DllImport(uxtheme.dll,ExactSpelling = true,CharSet = System.Runtime.InteropServices.CharSet .Unicode)]
public static extern int SetWindowTheme(
IntPtr hWnd,
String pszSubAppName,
String pszSubIdList);

// GetWindowRect User32函数
[System.Runtime.InteropServices.DllImport(user32.dll,ExactSpelling = true)]
[return:System.Runtime.InteropServices。 MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
public static extern bool GetWindowRect(
IntPtr hwnd,
RECT lpRect
);

// GetWindowDC User32函数
[System.Runtime.InteropServices.DllImport(user32.dll,ExactSpelling = true)]
public static extern IntPtr GetWindowDC(
IntPtr hWnd
);

// GetDCEx User32函数
[System.Runtime.InteropServices.DllImport(user32.dll,ExactSpelling = true)]
public static extern IntPtr GetDCEx(
IntPtr hWnd,
IntPtr hrgnClip,
int flags
);

//窗口过程钩子
保护覆盖无效WndProc(ref消息m)
{
//不要在设计器中设计样式窗口...
if(DesignMode)
base.WndProc(ref m);

//处理消息
switch((uint)m.Msg)
{
case WM_NCCALCSIZE:WmNCCalcSize(ref m);打破;
case WM_NCPAINT:WmNCPaint(ref m);打破;
默认值:base.WndProc(ref m);打破;


$ b $ //处理创建
protected override void OnHandleCreated(EventArgs e)
{
// Base Procedure ...
base.OnHandleCreated(e);

//删除主题
SetWindowTheme(this.Handle,string.Empty,string.Empty);
}

// WM_NCCALCSIZE
private void WmNCCalcSize(ref message m)
{
//获取窗口矩形
RECT formRect = new RECT();
GetWindowRect(m.HWnd,out formRect);

//检查WPARAM
if(m.WParam!= IntPtr.Zero)// TRUE
{
//当TRUE时,LPARAM指向NCCALCSIZE_PARAMS结构
var nccsp =(NCCALCSIZE_PARAMS)System.Runtime.InteropServices.Marshal.PtrToStructure(m.LParam,typeof(NCCALCSIZE_PARAMS));

//我们正在调整客户区的大小。目前,客户区是整个表单。
//添加到顶部,底部,左侧和右侧将调整客户区域的大小。
nccsp.rgrc0.top + = 30; // 30像素顶边框
nccsp.rgrc0.bottom - = 4; //底部4像素(调整大小)边框
nccsp.rgrc0.left + = 4; //左4像素(调整大小)边框
nccsp.rgrc0.right - = 4; //右边4像素(调整大小)边框

//将结构设置回内存
System.Runtime.InteropServices.Marshal.StructureToPtr(nccsp,m.LParam,true);
}
else // FALSE
{
//当FALSE时,LPARAM指向RECT结构
var clnRect =(RECT)System.Runtime.InteropServices.Marshal .PtrToStructure(m.LParam,typeof(RECT));

//和以前一样,我们正在调整矩形...
//添加到顶部,底部,左侧和右侧将调整客户区域的大小。
clnRect.top + = 30; // 30像素顶边框
clnRect.bottom - = 4; // 4像素底部(调整大小)边框
clnRect.left + = 4; //左4像素(调整大小)边框
clnRect.right - = 4; //右对齐4个像素(调整大小)

//将结构设置回内存
System.Runtime.InteropServices.Marshal.StructureToPtr(clnRect,m.LParam,true);
}

//返回零
m.Result = IntPtr.Zero;


// WM_NCPAINT
private void WmNCPaint(ref Message m)
{
// Store HDC
IntPtr HDC = IntPtr。零;
Graphics gfx = null;

//检查WPARAM
if(m.WParam ==(IntPtr)1)
{
//对于我未知的原因,更新区域不会不包含有效数据并且调用GetDCEx将不会执行任何操作。
//所以我调用GetWindowDC并使用System.Drawing.Graphics来排除该区域。

//来自HDC的图形对象
HDC = GetWindowDC(m.HWnd);
gfx = Graphics.FromHdc(HDC);

//排除客户区域
gfx.ExcludeClip(新的矩形(4,30,宽度-8,34)); //排除客户区(GetWindowDC抓取WHOLE窗口的图形句柄)
}
else
{
// HDC的图形对象
HDC = GetDCEx(m.HWnd ,m.WParam,DCX_WINDOW | DCX_INTERSECTRGN);
gfx = Graphics.FromHdc(HDC);
}

//使用(PaintEventArgs ncPaintArgs = new PaintEventArgs(gfx,new Rectangle(0,0,Width,Height)))
调用Paint b $ b MyForm_NCPaint这个,ncPaintArgs);

//返回零
m.Result = IntPtr.Zero;


public MyForm()
{
InitializeComponent();
}

private void MyForm_NCPaint(object sender,PaintEventArgs e)
{
//清除
e.Graphics.Clear(Color.Green);
}
}


I want to know if it's possible to set the client area of a borderless form. Say for example I define a form like so:

Code

public class MyForm : Form
{
    public MyForm()
    {
        this.FormBorderStyle = FormBorderStyle.None;
    }
}

Result

What I want to do is specify the client area, so that the form has a frame (like the standard windows frame, but custom drawn).

Result

Essentially, the blue area would become the non client area, and the gray area would remain as the client area.

I have tried to set the client area, but this just seems to resize the entire form, thus, is does not leave behind a "non-client" area

Is this possible?

解决方案

This is possible, however I don't know how well this works with a Windows Form with the WindowStyle set to Borderless. Using PInvoke (Platform Invoke) Functions, you can remove window themes which will give you a very basic looking Windows Form. You can then use various PInvoke functions to manipulate the Non-client area of the windows form.

I recommend that you read through these topics. They're designed for Win32 Applications using C++, but PInvoke is the process of calling these native APIs using Managed Code (C#)

WM_NCCALCSIZE: https://msdn.microsoft.com/en-us/library/windows/desktop/ms632634(v=vs.85).aspx

WM_NCPAINT: https://msdn.microsoft.com/en-us/library/windows/desktop/dd145212(v=vs.85).aspx

GetDCEx: https://msdn.microsoft.com/en-us/library/windows/desktop/dd144873(v=vs.85).aspx

GetWindowDC: https://msdn.microsoft.com/en-us/library/windows/desktop/dd144947(v=vs.85).aspx

SetWindowTheme: https://msdn.microsoft.com/en-us/library/windows/desktop/bb759827(v=vs.85).aspx

This example is very very crude, but it provides basic functionality. I don't know how SetWindowTheme works on Windows 8 or 8.1, but in Windows 7, it gives windows the "classic" theme.

public partial class MyForm : Form
{
    //Window Messages
    public const uint WM_NCPAINT = 0x85;
    public const uint WM_NCCALCSIZE = 0x83;
    public const uint WM_NCHITTEST = 0x84;

    //GetDCEx Flags
    public const int DCX_WINDOW = 0x00000001;
    public const int DCX_CACHE = 0x00000002;
    public const int DCX_PARENTCLIP = 0x00000020;
    public const int DCX_CLIPSIBLINGS = 0x00000010;
    public const int DCX_CLIPCHILDREN = 0x00000008;
    public const int DCX_NORESETATTRS = 0x00000004;
    public const int DCX_LOCKWINDOWUPDATE = 0x00000400;
    public const int DCX_EXCLUDERGN = 0x00000040;
    public const int DCX_INTERSECTRGN = 0x00000080;
    public const int DCX_INTERSECTUPDATE = 0x00000200;
    public const int DCX_VALIDATE = 0x00200000;

    //RECT Structure
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct RECT
    {
        public int left, top, right, bottom;
    }

    //WINDOWPOS Structure
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct WINDOWPOS
    {
        public IntPtr hwnd;
        public IntPtr hwndinsertafter;
        public int x, y, cx, cy;
        public int flags;
    }

    //NCCALCSIZE_PARAMS Structure
    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct NCCALCSIZE_PARAMS
    {
        public RECT rgrc0, rgrc1, rgrc2;
        public WINDOWPOS lppos;
    }

    //SetWindowTheme UXtheme Function
    [System.Runtime.InteropServices.DllImport("uxtheme.dll", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
    public static extern int SetWindowTheme(
        IntPtr hWnd,
        String pszSubAppName,
        String pszSubIdList);

    //GetWindowRect User32 Function
    [System.Runtime.InteropServices.DllImport("user32.dll", ExactSpelling = true)]
    [return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
    public static extern bool GetWindowRect(
        IntPtr hwnd,
        out  RECT lpRect
        );

    //GetWindowDC User32 Function
    [System.Runtime.InteropServices.DllImport("user32.dll", ExactSpelling = true)]
    public static extern IntPtr GetWindowDC(
        IntPtr hWnd
        );

    //GetDCEx User32 Function
    [System.Runtime.InteropServices.DllImport("user32.dll", ExactSpelling = true)]
    public static extern IntPtr GetDCEx(
        IntPtr hWnd,
        IntPtr hrgnClip,
        int flags
        );

    //Window Procedure Hook
    protected override void WndProc(ref Message m)
    {
        //Don't style window in designer...
        if (DesignMode)
            base.WndProc(ref m);

        //Handle Message
        switch ((uint)m.Msg)
        {
            case WM_NCCALCSIZE: WmNCCalcSize(ref m); break;
            case WM_NCPAINT: WmNCPaint(ref m); break;
            default: base.WndProc(ref m); break;
        }
    }

    //Handle Creation
    protected override void OnHandleCreated(EventArgs e)
    {
        //Base Procedure...
        base.OnHandleCreated(e);

        //Remove Theme
        SetWindowTheme(this.Handle, string.Empty, string.Empty);
    }

    //WM_NCCALCSIZE
    private void WmNCCalcSize(ref Message m)
    {
        //Get Window Rect
        RECT formRect = new RECT();
        GetWindowRect(m.HWnd, out formRect);

        //Check WPARAM
        if (m.WParam != IntPtr.Zero)    //TRUE
        {
            //When TRUE, LPARAM Points to a NCCALCSIZE_PARAMS structure
            var nccsp = (NCCALCSIZE_PARAMS)System.Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, typeof(NCCALCSIZE_PARAMS));

            //We're adjusting the size of the client area here. Right now, the client area is the whole form.
            //Adding to the Top, Bottom, Left, and Right will size the client area.
            nccsp.rgrc0.top += 30;      //30-pixel top border
            nccsp.rgrc0.bottom -= 4;    //4-pixel bottom (resize) border
            nccsp.rgrc0.left += 4;      //4-pixel left (resize) border
            nccsp.rgrc0.right -= 4;     //4-pixel right (resize) border

            //Set the structure back into memory
            System.Runtime.InteropServices.Marshal.StructureToPtr(nccsp, m.LParam, true);
        }
        else    //FALSE
        {
            //When FALSE, LPARAM Points to a RECT structure
            var clnRect = (RECT)System.Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, typeof(RECT));

            //Like before, we're adjusting the rectangle...
            //Adding to the Top, Bottom, Left, and Right will size the client area.
            clnRect.top += 30;      //30-pixel top border
            clnRect.bottom -= 4;    //4-pixel bottom (resize) border
            clnRect.left += 4;      //4-pixel left (resize) border
            clnRect.right -= 4;     //4-pixel right (resize) border

            //Set the structure back into memory
            System.Runtime.InteropServices.Marshal.StructureToPtr(clnRect, m.LParam, true);
        }

        //Return Zero
        m.Result = IntPtr.Zero;
    }

    //WM_NCPAINT
    private void WmNCPaint(ref Message m)
    {
        //Store HDC
        IntPtr HDC = IntPtr.Zero;
        Graphics gfx = null;

        //Check the WPARAM
        if(m.WParam == (IntPtr)1)
        {
            //For reasons unknown to me, the update region doesn't contain valid data and calling GetDCEx will do nothing.
            //So I call GetWindowDC and exclude the area using System.Drawing.Graphics instead.

            //Graphics Object from HDC
            HDC = GetWindowDC(m.HWnd);
            gfx = Graphics.FromHdc(HDC);

            //Exclude Client Area
            gfx.ExcludeClip(new Rectangle(4, 30, Width - 8, 34));  //Exclude Client Area (GetWindowDC grabs the WHOLE window's graphics handle)
        }
        else
        {
            //Graphics Object from HDC
            HDC = GetDCEx(m.HWnd, m.WParam, DCX_WINDOW | DCX_INTERSECTRGN);
            gfx = Graphics.FromHdc(HDC);
        }

        //Call Paint
        using (PaintEventArgs ncPaintArgs = new PaintEventArgs(gfx, new Rectangle(0, 0, Width, Height)))
            MyForm_NCPaint(this, ncPaintArgs);

        //Return Zero
        m.Result = IntPtr.Zero;
    }

    public MyForm()
    {
        InitializeComponent();
    }

    private void MyForm_NCPaint(object sender, PaintEventArgs e)
    {
        //Clear
        e.Graphics.Clear(Color.Green);
    }
}

这篇关于如何设置无边界形式的客户区(ClientRectangle)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆