如何设置Winform控件的ClientRectangle
生活随笔
收集整理的這篇文章主要介紹了
如何设置Winform控件的ClientRectangle
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
最近學習制作WinForm控件,自己動手寫控件的時候才發現System.Windows.Forms.Control 竟然沒有提供默認的border繪制。記得以前用API做控件的時候,只需要設置空間窗口的WS_BORDER?風格就可以。遍尋無方,只有自己繪制了,這里有出現一個,如果border在客戶區,那么在OnPaint方法里不得不每次都要考慮Border所占用的區域,而且,如果從這個類派生的話,將無法獲得準確的客戶區。
????? 現在要解決的問題就是如何重新設置客戶區的矩形區域的尺寸,查看了一下Control類的ClientRectangle屬性:
public?Rectangle?ClientRectangle?{?get;?}是個只讀屬性,看來是不能通過這個屬性達到目的了。再查找Control類的文檔,也沒有這方面的說明,沒有辦法,只能用API搞定了。可以通過計算非客戶區尺寸來設置客戶區尺寸,Border在非客戶繪制。下面就是主要的代碼,就是通過重載WndProc方法,捕捉WM_NCCALCSIZE消息,實現自己的邏輯。
????? protected?override?void?WndProc(ref?Message?m)
{
switch?(m.Msg)
{
case?(int)WinAPI_WM.WM_NCCALCSIZE:
if?(m.WParam.ToInt32()?==?0)
{
WinAPI_RECT?rc?=?(WinAPI_RECT)m.GetLParam(typeof(WinAPI_RECT));
rc.Left?+=?1;
rc.Top?+=?1;?
rc.Right?-=?1;?
rc.Bottom?-=?1;
Marshal.StructureToPtr(rc,?m.LParam,?true);
m.Result?=?IntPtr.Zero;
}
else
{
WinAPI_NCCALCSIZE_PARAMS?csp;
csp?=?(WinAPI_NCCALCSIZE_PARAMS)m.GetLParam(typeof(WinAPI_NCCALCSIZE_PARAMS));
csp.rgrc0.Top?+=?1;?
csp.rgrc0.Bottom?-=?1;
csp.rgrc0.Left?+=?1;?
csp.rgrc0.Right?-=?1;
Marshal.StructureToPtr(csp,?m.LParam,?true);
//Return?zero?to?preserve?client?rectangle
m.Result?=?IntPtr.Zero;
}
break;
case?(int)WinAPI_WM.WM_NCPAINT:
{
m.WParam?=?NCPaint(m.WParam);
break;
}
}
base.WndProc(ref?m);
}
public?IntPtr?NCPaint(IntPtr?region)
{
IntPtr?hDC?=?GetWindowDC(this.Handle);
if?(hDC?!=?IntPtr.Zero)
{
Graphics?grTemp?=?Graphics.FromHdc(hDC);
int?ScrollBarWidth?=?SystemInformation.VerticalScrollBarWidth;
int?ScrollBarHeight?=?SystemInformation.HorizontalScrollBarHeight;
WINDOWINFO?wi?=?new?WINDOWINFO();
wi.cbSize?=?(uint)Marshal.SizeOf(wi);
//得到當前控件的窗口信息
GetWindowInfo(Handle,?ref?wi);
wi.rcClient.Right--;
wi.rcClient.Bottom--;
//獲得當前控件的區域
Region?UpdateRegion?=?new?Region(new?Rectangle(wi.rcWindow.Top,wi.rcWindow.Left,wi.rcWindow.Right-wi.rcWindow.Left,wi.rcWindow.Bottom-wi.rcWindow.Top));
//獲得客戶區以外的區域
UpdateRegion.Exclude(new?Rectangle(wi.rcClient.Top,?wi.rcClient.Left,?wi.rcClient.Right?-?wi.rcClient.Left,?wi.rcClient.Bottom?-?wi.rcClient.Top));
if?(IsHScrollVisible?&&?IsVScrollVisible)
{
UpdateRegion.Exclude(Rectangle.FromLTRB
(wi.rcClient.Right?+?1,?wi.rcClient.Bottom?+?1,
wi.rcWindow.Right,?wi.rcWindow.Bottom));
}
//得到當前區域的句柄
IntPtr?hRgn?=?UpdateRegion.GetHrgn(grTemp);
//For?Painting?we?need?to?zero?offset?the?Rectangles.
Rectangle?WindowRect?=?new?Rectangle(wi.rcWindow.Top,?wi.rcWindow.Left,?wi.rcWindow.Right?-?wi.rcWindow.Left,?wi.rcWindow.Bottom?-?wi.rcWindow.Top);
Point?offset?=?Point.Empty?-?(Size)WindowRect.Location;
WindowRect.Offset(offset);
Rectangle?ClientRect?=?WindowRect;
ClientRect.Inflate(-1,?-1);
//Fill?the?BorderArea
Region?PaintRegion?=?new?Region(WindowRect);
PaintRegion.Exclude(ClientRect);
grTemp.FillRegion(SystemBrushes.Control,?PaintRegion);
//Fill?the?Area?between?the?scrollbars
if?(IsHScrollVisible?&&?IsVScrollVisible)
{
Rectangle?ScrollRect?=?new?Rectangle(ClientRect.Right?-?ScrollBarWidth,
ClientRect.Bottom?-?ScrollBarHeight,?ScrollBarWidth?+?2,?ScrollBarHeight?+?2);
ScrollRect.Offset(-1,?-1);
grTemp.FillRectangle(SystemBrushes.Control,?ScrollRect);
}
//Adjust?ClientRect?for?Drawing?Border.
ClientRect.Inflate(2,?2);
ClientRect.Width--;
ClientRect.Height--;
//Draw?Outer?Raised?Border
ControlPaint.DrawBorder3D(grTemp,?WindowRect,?Border3DStyle.Raised,
Border3DSide.Bottom?|?Border3DSide.Left?|?Border3DSide.Right?|?Border3DSide.Top);
//Draw?Inner?Sunken?Border
ControlPaint.DrawBorder3D(grTemp,?ClientRect,?Border3DStyle.Sunken,
Border3DSide.Bottom?|?Border3DSide.Left?|?Border3DSide.Right?|?Border3DSide.Top);
ReleaseDC(Handle,?hDC);
grTemp.Dispose();
return?hRgn;
}
RefreshScrollBar();
return?region;
}
????? 現在要解決的問題就是如何重新設置客戶區的矩形區域的尺寸,查看了一下Control類的ClientRectangle屬性:
public?Rectangle?ClientRectangle?{?get;?}是個只讀屬性,看來是不能通過這個屬性達到目的了。再查找Control類的文檔,也沒有這方面的說明,沒有辦法,只能用API搞定了。可以通過計算非客戶區尺寸來設置客戶區尺寸,Border在非客戶繪制。下面就是主要的代碼,就是通過重載WndProc方法,捕捉WM_NCCALCSIZE消息,實現自己的邏輯。
????? protected?override?void?WndProc(ref?Message?m)
{
switch?(m.Msg)
{
case?(int)WinAPI_WM.WM_NCCALCSIZE:
if?(m.WParam.ToInt32()?==?0)
{
WinAPI_RECT?rc?=?(WinAPI_RECT)m.GetLParam(typeof(WinAPI_RECT));
rc.Left?+=?1;
rc.Top?+=?1;?
rc.Right?-=?1;?
rc.Bottom?-=?1;
Marshal.StructureToPtr(rc,?m.LParam,?true);
m.Result?=?IntPtr.Zero;
}
else
{
WinAPI_NCCALCSIZE_PARAMS?csp;
csp?=?(WinAPI_NCCALCSIZE_PARAMS)m.GetLParam(typeof(WinAPI_NCCALCSIZE_PARAMS));
csp.rgrc0.Top?+=?1;?
csp.rgrc0.Bottom?-=?1;
csp.rgrc0.Left?+=?1;?
csp.rgrc0.Right?-=?1;
Marshal.StructureToPtr(csp,?m.LParam,?true);
//Return?zero?to?preserve?client?rectangle
m.Result?=?IntPtr.Zero;
}
break;
case?(int)WinAPI_WM.WM_NCPAINT:
{
m.WParam?=?NCPaint(m.WParam);
break;
}
}
base.WndProc(ref?m);
}
public?IntPtr?NCPaint(IntPtr?region)
{
IntPtr?hDC?=?GetWindowDC(this.Handle);
if?(hDC?!=?IntPtr.Zero)
{
Graphics?grTemp?=?Graphics.FromHdc(hDC);
int?ScrollBarWidth?=?SystemInformation.VerticalScrollBarWidth;
int?ScrollBarHeight?=?SystemInformation.HorizontalScrollBarHeight;
WINDOWINFO?wi?=?new?WINDOWINFO();
wi.cbSize?=?(uint)Marshal.SizeOf(wi);
//得到當前控件的窗口信息
GetWindowInfo(Handle,?ref?wi);
wi.rcClient.Right--;
wi.rcClient.Bottom--;
//獲得當前控件的區域
Region?UpdateRegion?=?new?Region(new?Rectangle(wi.rcWindow.Top,wi.rcWindow.Left,wi.rcWindow.Right-wi.rcWindow.Left,wi.rcWindow.Bottom-wi.rcWindow.Top));
//獲得客戶區以外的區域
UpdateRegion.Exclude(new?Rectangle(wi.rcClient.Top,?wi.rcClient.Left,?wi.rcClient.Right?-?wi.rcClient.Left,?wi.rcClient.Bottom?-?wi.rcClient.Top));
if?(IsHScrollVisible?&&?IsVScrollVisible)
{
UpdateRegion.Exclude(Rectangle.FromLTRB
(wi.rcClient.Right?+?1,?wi.rcClient.Bottom?+?1,
wi.rcWindow.Right,?wi.rcWindow.Bottom));
}
//得到當前區域的句柄
IntPtr?hRgn?=?UpdateRegion.GetHrgn(grTemp);
//For?Painting?we?need?to?zero?offset?the?Rectangles.
Rectangle?WindowRect?=?new?Rectangle(wi.rcWindow.Top,?wi.rcWindow.Left,?wi.rcWindow.Right?-?wi.rcWindow.Left,?wi.rcWindow.Bottom?-?wi.rcWindow.Top);
Point?offset?=?Point.Empty?-?(Size)WindowRect.Location;
WindowRect.Offset(offset);
Rectangle?ClientRect?=?WindowRect;
ClientRect.Inflate(-1,?-1);
//Fill?the?BorderArea
Region?PaintRegion?=?new?Region(WindowRect);
PaintRegion.Exclude(ClientRect);
grTemp.FillRegion(SystemBrushes.Control,?PaintRegion);
//Fill?the?Area?between?the?scrollbars
if?(IsHScrollVisible?&&?IsVScrollVisible)
{
Rectangle?ScrollRect?=?new?Rectangle(ClientRect.Right?-?ScrollBarWidth,
ClientRect.Bottom?-?ScrollBarHeight,?ScrollBarWidth?+?2,?ScrollBarHeight?+?2);
ScrollRect.Offset(-1,?-1);
grTemp.FillRectangle(SystemBrushes.Control,?ScrollRect);
}
//Adjust?ClientRect?for?Drawing?Border.
ClientRect.Inflate(2,?2);
ClientRect.Width--;
ClientRect.Height--;
//Draw?Outer?Raised?Border
ControlPaint.DrawBorder3D(grTemp,?WindowRect,?Border3DStyle.Raised,
Border3DSide.Bottom?|?Border3DSide.Left?|?Border3DSide.Right?|?Border3DSide.Top);
//Draw?Inner?Sunken?Border
ControlPaint.DrawBorder3D(grTemp,?ClientRect,?Border3DStyle.Sunken,
Border3DSide.Bottom?|?Border3DSide.Left?|?Border3DSide.Right?|?Border3DSide.Top);
ReleaseDC(Handle,?hDC);
grTemp.Dispose();
return?hRgn;
}
RefreshScrollBar();
return?region;
}
轉載于:https://www.cnblogs.com/guanjinke/archive/2006/11/29/576961.html
總結
以上是生活随笔為你收集整理的如何设置Winform控件的ClientRectangle的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux服务器网卡驱动安装及故障排除(
- 下一篇: 导入他人的想法