(三)---
设置窗体的Region
经过上面两篇的界面开发,我们使用Windows的Hook技术,成功的将系统中的窗体的消息截取,并添加了自己的事件处理程序,这篇文章就是通过我们对这些消息的处理的第一步,设置窗体的样式和窗体的Region。
Region对于窗体来说是一个非常重要的概念,他就是Windows分配给窗体显示的区域,所以,我们第一步就是根据我们的需要设计我们的窗体区域。而对于Windows窗体区域的设置,WndProc中的STYLECHANGED,SHOWWINDOW,SIZE,WINDOWPOSCHANGED都有可能用到。这些方法都对窗体的样式或者窗体的大小就行了修改,所以我们也要对这几个消息进行处理。
首先我们创建一个类用来设置窗体的显示,名称为SkinAppearance.cs,在这个文件中我添加了一个方法,叫做SetRegion,并且参数设置成为我们的窗体SkinningForm。SetRegion的代码如下:
/// <summary>
/// Set SkinningForm Region
/// </summary>
/// <param name="from">form to set region</param>
public void SetRegion(SkinningForm form)
{
// Check Form
if (form == null)
{
return;
}
// Get Form Size
Size size = form.Size;
// Set Color Size
Size cornerSize = new Size(90, 90);
// Create Region Handle
IntPtr hRegion = NativeMethod.CreateRoundRectRgn(0, 0, size.Width + 1, size.Height + 1, cornerSize.Width, cornerSize.Height);
Region region = Region.FromHrgn(hRegion);
// Set Region
form.Region = region;
region.ReleaseHrgn(hRegion);
}
这样我们就设置了我们的窗体样式,其中cornerSize我设置的比较大,这样显示的效果比较明显。显示的窗体如下:
这样的显示比较难看,这是因为我们还没有对窗体进行其他的绘画。当然我们也可以通过这个方法对窗体的显示进行其他的操作。下一篇将使用GDI+对窗体进行绘画,主要对窗体的边框进行设计。
本篇代码下载:SkinEngines20100322.rar
(四)--- 还窗体的新面貌
前一篇给窗体设置了Region,将窗体的FormBorderStyle设置成了None,然后修改了窗体的显示区域Region。一个本来完好的窗体让我们设置成为了一个空白的没有任何色彩的窗体,这对我们的界面开发好像是背到而行,有点南辕北辙了。其实不然,只有将窗体上的所有原有的信息给去除掉,才能还原窗体的本来面貌,给窗体一个新面貌。
这篇就对窗体的界面开发设计一个新面貌。
我在界面开篇的开篇就已经说过,界面开发其实就是修改窗体的两个区域,Client Area和None
Client Area,如下图:
而我们现在已经将窗体修改成了没有任何信息的窗体,如下图:
现在我们要做的,就是在这个什么都没有的图上添加上我们自己的界面,将窗体的Client Area和None
Client Area从新绘制让其有新的面貌。而他的绘制确实需要很多的GDI+知识。
Client Area的绘画很简单,主要就是对窗体的背景色进行修改,这个对于C#开发人员就是一句话的事情,设置窗体的背景色就可以了。代码如下:
this._parentForm.BackColor = this._engine.SkinColor.Back;
但是,对于None Client Area的绘画就比较麻烦,他不仅仅画的是颜色,还有窗体的标题栏、最大化、最小化、关闭按钮、窗体图标和窗体的边框,接下来就是一一对窗体的进行绘画。
窗体的标题栏分为两大部分:窗体的图标和窗体的标题,绘画这些的第一步都是对窗体的绘画区域的设置。找到绘画的区域,然后使用GDI+进行绘画,具体的过程就是这样,代码如下:
#region NcPaint
/// <summary>
/// NcPaint
/// </summary>
/// <param name="form"></param>
/// <returns></returns>
private bool NcPaint(SkinningForm form, SkinEngine engine)
{
// Declared Filed
bool result = true;
IntPtr hdc = (IntPtr)0;
Graphics g = null;
Region region = null;
IntPtr hrgn = (IntPtr)0;
try
{
// Get Rect
RECT rectScreen = new RECT();
NativeMethod.GetWindowRect(_parentForm.Handle, ref rectScreen);
Rectangle rectBounds = rectScreen.ToRectangle();
rectBounds.Offset(-rectBounds.X, -rectBounds.Y);
// prepare clipping
Rectangle rectClip = rectBounds;
region = new Region(rectClip);
rectClip.Inflate(-engine.SkinAppearance.BorderWidth, -engine.SkinAppearance.BorderWidth);
rectClip.Y += engine.SkinAppearance.CaptionHeight;
rectClip.Height -= engine.SkinAppearance.CaptionHeight;
// create graphics handle
hdc = NativeMethod.GetDCEx(_parentForm.Handle, (IntPtr)0,
(DCXFlags.DCX_CACHE | DCXFlags.DCX_CLIPSIBLINGS | DCXFlags.DCX_WINDOW));
g = Graphics.FromHdc(hdc);
// Apply clipping
region.Exclude(rectClip);
hrgn = region.GetHrgn(g);
NativeMethod.SelectClipRgn(hdc, hrgn);
if (_bufferGraphics == null || _currentCacheSize != rectBounds.Size)
{
if (_bufferGraphics != null)
_bufferGraphics.Dispose();
_bufferGraphics = _bufferContext.Allocate(g, new Rectangle(0, 0,
rectBounds.Width, rectBounds.Height));
_currentCacheSize = rectBounds.Size;
}
// Get Caption Bounds
Rectangle captionBounds = rectBounds;
captionBounds.Height = this._engine.SkinAppearance.BorderWidth + this._engine.SkinAppearance.CaptionHeight;
// Draw Caption
engine.SkinAppearance.DrawCaptionBackground(g, captionBounds, this._formIsActive, this._engine);
// Draw Caption Icon
if (this._parentForm.ShowIcon && this._parentForm.Icon != null)
{
DrawIcon(g);
}
// Draw Caption Text
DrawCaptionText(g, this._parentForm.Text, this._parentForm.Font);
// Draw Caption Button
DrawCaptionControlBox(g);
// Draw Border
engine.SkinAppearance.DrawBorder(g, rectBounds, engine);
}
catch
{
result = false;
}
// cleanup data
if (hdc != (IntPtr)0)
{
NativeMethod.SelectClipRgn(hdc, (IntPtr)0);
NativeMethod.ReleaseDC(_parentForm.Handle, hdc);
}
if (region != null && hrgn != (IntPtr)0)
region.ReleaseHrgn(hrgn);
if (region != null)
region.Dispose();
if (g != null)
g.Dispose();
return result;
}
#endregion
这个就完全绘制了窗体的边框。界面效果如下:
代码下载地址:SkinEngines20100324.rar
(五)--- 界面优化
在上一篇界面开发中,我讲解了将系统界面还原,还原窗体的本来面貌。但是有的博友提出窗体闪烁,这确实是个问题,原来自己开发的时候也是出现了这个问题。花了两天的时间,重要修改了个大概,将窗体绘画的次数和窗体的刷新程度进行了修改。首先看看效果:
这是主窗体,在主窗体中不仅修改了窗体的刷新率,而且添加了一个自定义的窗体按钮,使用了很多的颜色来显示,模仿了Foxmail的界面显示,但是对于除了主窗体外的其他窗体,这些是不存在的。如下图显示的子窗体:
实现的原理和原来的一样,只不过在原来绘画的基础上减少了绘画的内容和绘画区域的大小,这样窗体的界面效果就好多了。下一期将使用上面那个彩色的俺就对窗体进行修改变色。
本期代码如下:SkinEngines20100326.rar
|