服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#实现属于自己的QQ截图工具

C#实现属于自己的QQ截图工具

2021-11-17 14:28C#教程网 C#

这篇文章主要为大家详细介绍了C#实现属于自己的QQ截图工具的相关资料,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

下面就具体介绍下实现截图工具的实现思路。

为了让大家更清楚地知道如何去实现自己的截图工具,首先我来描述下截图的一个过程——我们使用qq的截图工具和windows 自带的截图工具都可以发现,当我们点击qq窗体中的截图按钮时,此时我们将看到一个全屏图片,然后我们可以在其上截图,当鼠标左键按下时,即代表开始截图,并我们可以移动鼠标来改变截图的大小,鼠标弹起时即代表结束截图,此时我们可以双击矩形区域完全截图,并且可以通过粘贴操作把截取的图片粘贴到聊天窗口的发送区,鼠标右键点击则是退出截图。这样我们截图的过程描述就是这样的,从这个描述中我们就可以抽象出实现我们截图工具的思路来:

从 “此时我们将看到一个全屏图片”这句话描述我们应该抽象为——对于qq截图工具的实现来说,我们看到的这个全屏图片其实并不是一张“图片”(这里最好不要钻空子),而是一个窗体,这个窗体我们命名为 “截图窗体”,只是把窗体的背景图片设置为全屏图片。说到这里,一些没有研究过qq截图工具的人开始有疑问了——我们看到的是窗体?那为什么边框的,即没有最大化按钮,最下化按钮的呢?(对于这点的解释就是,程序中可以设置form的borderstyle属性为none的方式来隐藏掉边框)。
既然要设置窗体的背景图片为全屏图片,我们知道设置背景图片只需要设置窗体的backgroundimage属性就好了,但是全屏图片怎么获取呢?既然是全屏图片,自然我就应该使窗体最大化话了,不然我们看到只是一个没有边框的“小图片”了,而不是一个全屏的图片。下面是具体实现这个分析的代码:           

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 通过graphics的copyfromscreen方法把全屏图片的拷贝到我们定义好的一个和屏幕大小相同的空白图片中,
 // 拷贝完成之后,catchbmp就是全屏图片的拷贝了,然后指定为截图窗体背景图片就好了。
 // 新建一个和屏幕大小相同的图片
 bitmap catchbmp = new bitmap(screen.allscreens[0].bounds.width, screen.allscreens[0].bounds.height);
 
 // 创建一个画板,让我们可以在画板上画图
 // 这个画板也就是和屏幕大小一样大的图片
 // 我们可以通过graphics这个类在这个空白图片上画图
 graphics g = graphics.fromimage(catchbmp);
 
 // 把屏幕图片拷贝到我们创建的空白图片 catchbmp中
 g.copyfromscreen(new point(0, 0), new point(0, 0), new size(screen.allscreens[0].bounds.width, screen.allscreens[0].bounds.height));
 
 // 创建截图窗体
 cutter = new cutter();
 
 // 指示窗体的背景图片为屏幕图片
 cutter.backgroundimage = catchbmp;

3. 从 “然后我们可以在其上截图”这句话中我们抽象为——其实我们截图操作,从程序角度来说就是我们在这个最大化的窗体中画图,可能这个对一些不了解gdi+画图的朋友有些难理解,这里做个比喻——我们会拿笔在纸上画图,我们可以用比画三角形,矩形已经各种图形,此时纸就是我们一个画板,笔是用来画图图形的,同时笔也是有颜色和粗细的,我们可以用红色水笔画,画出来的图就是红色的了,也可以用黑色水笔画,自然画出来的就是黑色的了,同样,在gdi+也就是graphics device interface plus也就是图形设备接口,在.net 中也提供了一些这样的类来让我们实现对图像的访问,也就是我们可以使用.net中提供的类来进行 “画画”,要画画当然必须要有画板吧(我们开始比喻中纸就是画板),在.net 类中graphics类就是对画板的抽象,画板可以由三种方式创建:(1)从图片或继承自图像对象中创建;(2)从窗体或控件的paint事件中创建;(3)利用窗体或控件的creategraphics方法创建。有了画板之后,当然就需要笔来画画了,在.net 中pen类就是起到笔的作用,在构造函数中可以指定笔的颜色和粗细,有了笔之后就是开始画图了,在.net中也同样提供了一些方法来完成画图,如drawrectangle方法——画矩形

4. 从 “当鼠标左键按下时,即代表开始截图,并我们可以移动鼠标来改变截图的大小,鼠标弹起时即代表结束截图,此时我们可以双击矩形区域完全截图,并且可以通过粘贴操作把截取的图片粘贴到聊天窗口的发送区,鼠标右键点击则是退出截图”这些描述中可以抽象为——鼠标的移动,按下,弹起等操作,在程序角度来说,也就是实现截图窗体的mousemove事件(对应于鼠标移动),mousedown事件(对应于鼠标左键按下),mouseclick事件(对应于鼠标右键结束截图)、mouseup(对应于鼠标弹起结束截图)和mousedoubleclick(鼠标双击矩形区域完全截图,并可以通过粘贴操作把截取的图片粘贴到聊天窗口的发送区,既然可以进行粘贴操作来获得截取图片,所以必须在该事件中对剪切板设置截图图片),3和4的分析过程也是截图功能的核心实现,对应于下面的代码(代码中有详细解释,并且大家理解的时候可以结合3和4的分析):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/// <summary>
/// 鼠标右键点击结束截图
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cutter_mouseclick(object sender, mouseeventargs e)
{
if (e.button == mousebuttons.right)
{
this.dialogresult = dialogresult.ok;
this.close();
}
}
 
/// <summary>
/// 鼠标按下事件处理程序
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cutter_mousedown(object sender, mouseeventargs e)
{
// 鼠标左键按下是开始画图,也就是截图
if (e.button == mousebuttons.left)
{
// 如果捕捉没有开始
if (!catchstart)
{
catchstart = true;
// 保存此时鼠标按下坐标
downpoint = new point(e.x, e.y);
}
}
}
 
/// <summary>
/// 鼠标移动事件处理程序,即用户改变截图大小的处理
/// 这个方法是截图功能的核心方法,也就是绘制截图
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cutter_mousemove(object sender, mouseeventargs e)
{
// 确保截图开始
if (catchstart)
{
// 新建一个图片对象,让它与屏幕图片相同
bitmap copybmp = (bitmap)originbmp.clone();
 
// 获取鼠标按下的坐标
point newpoint = new point(downpoint.x, downpoint.y);
 
// 新建画板和画笔
graphics g = graphics.fromimage(copybmp);
pen p = new pen(color.red, 1);
 
// 获取矩形的长宽
int width = math.abs(e.x - downpoint.x);
int height = math.abs(e.y-downpoint.y);
if (e.x < downpoint.x)
{
newpoint.x = e.x;
}
if (e.y < downpoint.y)
{
newpoint.y = e.y;
}
 
catchrectangle = new rectangle(newpoint, new size(width,height));
 
// 将矩形画在画板上
g.drawrectangle(p, catchrectangle);
 
// 释放目前的画板
g.dispose();
p.dispose();
// 从当前窗体创建新的画板
graphics g1 = this.creategraphics();
 
// 将刚才所画的图片画到截图窗体上
// 为什么不直接在当前窗体画图呢?
// 如果自己解决将矩形画在窗体上,会造成图片抖动并且有无数个矩形
// 这样实现也属于二次缓冲技术
g1.drawimage(copybmp, new point(0, 0));
g1.dispose();
// 释放拷贝图片,防止内存被大量消耗
copybmp.dispose();
}
}
 
/// <summary>
/// 鼠标左键弹起事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cutter_mouseup(object sender, mouseeventargs e)
{
if (e.button == mousebuttons.left)
{
// 如果截图已经开始,鼠标左键弹起设置截图完成
if (catchstart)
{
catchstart = false;
catchfinished = true;
}
}
}
 
/// <summary>
/// 鼠标双击事件,如果鼠标位于矩形内,则将矩形内的图片保存到剪切板中
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cutter_mousedoubleclick(object sender, mouseeventargs e)
{
if (e.button == mousebuttons.left && catchfinished)
{
// 新建一个与矩形一样大小的空白图片
bitmap catchedbmp = new bitmap(catchrectangle.width, catchrectangle.height);
 
graphics g = graphics.fromimage(catchedbmp);
 
// 把originbmp中指定部分按照指定大小画到空白图片上
// catchrectangle指定originbmp中指定部分
// 第二个参数指定绘制到空白图片的位置和大小
// 画完后catchedbmp不再是空白图片了,而是具有与截取的图片一样的内容
g.drawimage(originbmp, new rectangle(0, 0, catchrectangle.width, catchrectangle.height), catchrectangle, graphicsunit.pixel);
 
// 将图片保存到剪切板中
clipboard.setimage(catchedbmp);
g.dispose();
catchfinished = false;
this.backgroundimage = originbmp;
catchedbmp.dispose();
this.dialogresult = dialogresult.ok;
this.close();
}
}

5、到第4点为止,截图的功能已经分析完了,之后就是当我们使用qq截图的时候,我们除了可以点击聊天窗口中的截图按钮来进行截图外,还可以通过按下alt+ctrl+a来进行截图,要实现这个功能的思路也很简单——即当聊天窗体加载的时候对热键(程序中我定义的热键是“alt+ctrl+c”)进行注册(此时调用了win32中registerhotkey方法来完成热键的注册),当聊天窗体关闭时进行对热键的卸载,防止对热键进行多次注册,此时调用win32中的unregisterhotkey方法来完成,具体的实现代码为:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/// <summary>
/// 窗体加载事件处理
/// 在窗体加载时注册热键
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void 聊天窗体_load(object sender, eventargs e)
{
uint ctrlhotkey = (uint)(keymodifiers.alt|keymodifiers.ctrl);
// 注册热键为alt+ctrl+c, "100"为唯一标识热键
hotkey.registerhotkey(handle, 100, ctrlhotkey, keys.c);
}
 
/// <summary>
/// 窗体关闭时处理程序
/// 窗体关闭时取消热键注册
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void 聊天窗体_formclosing(object sender, formclosingeventargs e)
{
// 卸载热键
hotkey.unregisterhotkey(handle, 100);
}
 
#endregion
 
// 热键按下执行的方法
private void globalkeyprocess()
{
this.windowstate = formwindowstate.minimized;
// 窗口最小化也需要一定时间
thread.sleep(200);
btncutter.performclick();
}
 
/// <summary>
/// 重写wndproc()方法,通过监视系统消息,来调用过程
/// 监视windows消息
/// </summary>
/// <param name="m"></param>
protected override void wndproc(ref message m)
{
//如果m.msg的值为0x0312那么表示用户按下了热键
const int wm_hotkey = 0x0312;
switch (m.msg)
{
case wm_hotkey:
if (m.wparam.tostring() == "100")
{
globalkeyprocess();
}
 
break;
}
 
// 将系统消息传递自父类的wndproc
base.wndproc(ref m);
}

实现效果
上面已经介绍了实现qq截图的一个思路的,朋友们是不是迫不及待想看看该程序的一个效果了?下面就通过一个动画来让大家更形象地看到程序的运行效果的:

C#实现属于自己的QQ截图工具

qq截图工具下载:下载地址

总结

到这里qq截图的介绍部分就到这里了,本工具的实现自认为讲解的非常通俗易懂的,希望大家可以这样觉得并且可以更清晰地明白qq截图的实现思路。

延伸 · 阅读

精彩推荐
  • C#SQLite在C#中的安装与操作技巧

    SQLite在C#中的安装与操作技巧

    SQLite,是一款轻型的数据库,用于本地的数据储存。其优点有很多,下面通过本文给大家介绍SQLite在C#中的安装与操作技巧,感兴趣的的朋友参考下吧...

    蓝曈魅11162022-01-20
  • C#C#微信公众号与订阅号接口开发示例代码

    C#微信公众号与订阅号接口开发示例代码

    这篇文章主要介绍了C#微信公众号与订阅号接口开发示例代码,结合实例形式简单分析了C#针对微信接口的调用与处理技巧,需要的朋友可以参考下...

    smartsmile20127762021-11-25
  • C#如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    这篇文章主要给大家介绍了关于如何使用C#将Tensorflow训练的.pb文件用在生产环境的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴...

    bbird201811792022-03-05
  • C#深入理解C#的数组

    深入理解C#的数组

    本篇文章主要介绍了C#的数组,数组是一种数据结构,详细的介绍了数组的声明和访问等,有兴趣的可以了解一下。...

    佳园9492021-12-10
  • C#VS2012 程序打包部署图文详解

    VS2012 程序打包部署图文详解

    VS2012虽然没有集成打包工具,但它为我们提供了下载的端口,需要我们手动安装一个插件InstallShield。网上有很多第三方的打包工具,但为什么偏要使用微软...

    张信秀7712021-12-15
  • C#三十分钟快速掌握C# 6.0知识点

    三十分钟快速掌握C# 6.0知识点

    这篇文章主要介绍了C# 6.0的相关知识点,文中介绍的非常详细,通过这篇文字可以让大家在三十分钟内快速的掌握C# 6.0,需要的朋友可以参考借鉴,下面来...

    雨夜潇湘8272021-12-28
  • C#利用C#实现网络爬虫

    利用C#实现网络爬虫

    这篇文章主要介绍了利用C#实现网络爬虫,完整的介绍了C#实现网络爬虫详细过程,感兴趣的小伙伴们可以参考一下...

    C#教程网11852021-11-16
  • C#C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    这篇文章主要介绍了C#设计模式之Strategy策略模式解决007大破密码危机问题,简单描述了策略模式的定义并结合加密解密算法实例分析了C#策略模式的具体使用...

    GhostRider10972022-01-21