前面的三篇文章(CaptureImageTool做好了准备工作,今天就来把整个截图控件的功能全部实现。
这个截图控件需要实现的功能包括:截图、绘制矩形、圆形、箭头、线条、文字,还需要可以撤销绘制步骤、保存图形,把QQ截图拥有的功能基本都实现。先来看看最终的效果,然后再来介绍实现过程。
下面来一步步的介绍怎样实现这个截图控件:
1、截图。截图的原理很简单,网上都很多了,还是介绍一下吧。先利用API把整个屏幕拷贝到一个Image中,然后建立一个无标题栏的窗体,把它的背景图设为这个Image就行了。看看截图的函数:
privateImage GetDestopImage()
...{
Rectangle rect=Screen.GetBounds(this);
Bitmap bmp=newBitmap(
rect.Width, rect.Height, PixelFormat.Format32bppArgb);
Graphics g=Graphics.FromImage(bmp);
IntPtr gHdc=g.GetHdc();
IntPtr deskHandle=NativeMethods.GetDesktopWindow();
IntPtr dHdc=NativeMethods.GetDC(deskHandle);
NativeMethods.BitBlt(
gHdc,
0,
0,
Width,
Height,
dHdc,
0,
0,
NativeMethods.TernaryRasterOperations.SRCCOPY);
NativeMethods.ReleaseDC(deskHandle, dHdc);
g.ReleaseHdc(gHdc);
returnbmp;
}
2、选择截图区域。记录鼠标按下时的坐标,当鼠标移动时得到鼠标所在的坐标,通过这两个坐标就可以得到选择的矩形区域了,通过OnPaint方法画出所选择的区域,当鼠标放开时,就得到最终选取的截图区域了,需要记录下这个区域,下面很多地方需要用到它。
3、调整截图区域的大小和位置。这个实现稍微麻烦些,当鼠标移动的时候,需要判断鼠标是否处于我们设置的调节截图区域大小所在的小矩形内,是的话就改变鼠标指针的样式,提示用户这里按下鼠标可以改变截图区域的大小和位置。当用户在这个地方按下鼠标后,移动鼠标,就可以通过原来记录下来的截图区域和当前鼠标所在的位置调整截图区域的大小了。当放开鼠标后,需要保存这个新的截图区域。
4、实现绘图。利用前面已经实现的绘图工具栏和颜色字体选择控件,可以选择相应的图形进行绘制。简单的说就是根据鼠标的选择区域,绘制相应的图形,实现起来比较复杂,特别是文字和线条的绘制,不是简单的几句话可以介绍出来的,大家还是参照源代码自己体会吧。
5、实现撤销功能。要实现撤销功能,在前面绘图的时候,我们需要记录下每一步绘图完成的时候的动作,撤销绘图就可以返回到上一步,然后重绘。程序中实现了一个简单的操作管理的类OperateManager,可以方便的增加一步操作和移除一步操作。管理类最多纪录1000个操作,当超过1000个时,就会把第一个操作丢掉。看看这个类的完整代码:
internalclassOperateManager : IDisposable
...{
privateList_operateList;
privatestaticreadonlyintMaxOperateCount=1000;
publicOperateManager()
...{
}
publicListOperateList
...{
get
...{
if(_operateList==null)
...{
_operateList=newList(100);
}
return_operateList;
}
}
publicintOperateCount
...{
get...{returnOperateList.Count; }
}
publicvoidAddOperate(
OperateType operateType,
Color color,
objectdata)
...{
OperateObject obj=newOperateObject(
operateType, color, data);
if(OperateList.Count>MaxOperateCount)
...{
OperateList.RemoveAt(0);
}
OperateList.Add(obj);
}
publicboolRedoOperate()
...{
if(OperateList.Count>0)
...{
OperateList.RemoveAt(OperateList.Count-1);
returntrue;
}
returnfalse;
}
publicvoidClear()
...{
OperateList.Clear();
}
IDisposable 成员#regionIDisposable 成员
publicvoidDispose()
...{
if(_operateList!=null)
...{
_operateList.Clear();
_operateList=null;
}
}
#endregion
}
6、完成和保存截图。双击截图选择区域或者通过绘图工具栏的完成按钮和快捷菜单的完成项。当完成截图时,把选择的图形和所进行的画图操作全部绘制到一个新的Image中,把这个Image返回给用户。绘制通过下面这个函数实现:
privatevoidDrawLastImage()
...{
using(Bitmap allBmp=newBitmap(
Width, Height, PixelFormat.Format32bppArgb))
...{
using(Graphics allGraphics=Graphics.FromImage(allBmp))
...{
allGraphics.InterpolationMode=
InterpolationMode.HighQualityBicubic;
allGraphics.SmoothingMode=SmoothingMode.AntiAlias;
allGraphics.DrawImage(
BackgroundImage,
Point.Empty);
DrawOperate(allGraphics);
allGraphics.Flush();
Bitmap bmp=newBitmap(
SelectImageRect.Width,
SelectImageRect.Height,
PixelFormat.Format32bppArgb);
Graphics g=Graphics.FromImage(bmp);
g.DrawImage(
allBmp,
0,
0,
SelectImageRect,
GraphicsUnit.Pixel);
g.Flush();
g.Dispose();
_image=bmp;
}
}
}
7、取消截图。实现了跟QQ截图类似的取消截图方法,鼠标右键双击非选择的截图区域,或者点击绘图工具栏的退出按钮和快捷菜单的退出项。
8、改变颜色风格。实现了一个颜色表类CaptureImageToolColorTable,只需要继承这个类,相应的改变颜色,然后把CaptureImageTool的ColorTable设为它,就可以得到自己的不同的颜色风格了。看看颜色表类:
publicclassCaptureImageToolColorTable
...{
privatestaticreadonlyColor _borderColor=Color.FromArgb(65,173,236);
privatestaticreadonlyColor _backColorNormal=Color.FromArgb(229,243,251);
privatestaticreadonlyColor _backColorHover=Color.FromArgb(65,173,236);
privatestaticreadonlyColor _backColorPressed=Color.FromArgb(24,142,206);
privatestaticreadonlyColor _foreColor=Color.FromArgb(12,83,124);
publicCaptureImageToolColorTable()...{ }
publicvirtualColor BorderColor
...{
get...{return_borderColor; }
}
publicvirtualColor BackColorNormal
...{
get...{return_backColorNormal; }
}
publicvirtualColor BackColorHover
...{
get...{return_backColorHover; }
}
publicvirtualColor BackColorPressed
...{
get...{return_backColorPressed; }
}
publicvirtualColor ForeColor
...{
get...{return_foreColor; }
}
}
9、改变鼠标样式。通过设置CaptureImageTool的SelectCursor和DrawCursor属性,可以改变截图和绘图时的鼠标样式,程序还提供了一个鼠标管理类CursorManager,你可以用它来设置自己的不同的鼠标,看看源代码:
internalclassCursorManager
...{
publicstaticreadonlyCursor Arrow=
CreateCursor("Cursors//Arrow.cur");
publicstaticreadonlyCursor Cross=
CreateCursor("Cursors//Cross.cur");
publicstaticreadonlyCursor ArrowNew=
CreateCursor("Cursors//ArrowNew.cur");
publicstaticreadonlyCursor CrossNew=
CreateCursor("Cursors//CrossNew.cur");
privateCursorManager()...{ }
publicCursor CreateCursor(Bitmap cursor, Point hotPoint)
...{
inthotX=hotPoint.X;
inthotY=hotPoint.Y;
using(Bitmap cursorBmp=newBitmap(
cursor.Width*2-hotX,
cursor.Height*2-hotY,
PixelFormat.Format32bppArgb))
...{
using(Graphics g=Graphics.FromImage(cursorBmp))
...{
g.Clear(Color.FromArgb(0,0,0,0));
g.DrawImage(
cursor,
cursor.Width-hotX,
cursor.Height-hotY,
cursor.Width,
cursor.Height);
g.Flush();
}
returnnewCursor(cursorBmp.GetHicon());
}
}
publicstaticCursor CreateCursor(stringfileName)
...{
IntPtr cursorHandle=LoadCursorFromFile(fileName);
returnnewCursor(cursorHandle);
}
[DllImport("user32.dll")]
privatestaticexternIntPtr LoadCursorFromFile(stringfileName);
[DllImport("user32.dll")]
privatestaticexternuintDestroyCursor(IntPtr cursorHandle);
}
还有一些实现的具体细节就不一一介绍了,这里将提供完整源代码下载,大家从代码中了解吧,由于时间有限,都没来得及写注释,但是代码的命名还算规范吧,相信认真阅读是能看懂的。
声明:
本文版权归作者和CS程序员之窗所有,欢迎转载,转载必须保留以下版权信息,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
作者:Starts_2000
你可以免费使用或修改提供的源代码,但请保留源代码中的版权信息,详情请查看: