对于qq截图,肯定是早就有认识了,只是一直没有去认真观察这个操作的具体实现步骤。所以这里将自己的记忆中的步骤简单的写一下:
习惯性用qq或者tim的人,一般是使用ctrl+alt+a 快捷键(热键)快速实现截图。
- ctrl+alt+a 进入截图模式
- 鼠标左键点击
- 鼠标拖动对截图去进行选取
- 鼠标左键弹起
- 双击截图区域 保存图片到剪贴板
- 鼠标右键点击
- 退出截图模式
因为考虑到截图模式的时候 一般只能显示一个窗体 所以就考虑使用单例模式 在screenbody窗体中实现以下代码
1:创建单例
1
|
private static screenbody screenbody= null ;
|
2:私有化构造函数
1
2
3
4
|
private screenbody()
{
initializecomponent();
}
|
3:创建静态方法
1
2
3
4
5
6
7
8
|
private static screenbody getsingle()
{
if (screenbody== null )
{
screenbody= new screenbody();
}
return screenbody;
}
|
进一步讨论一下在main窗体中的调用 main中添加了一个button 命名为btncutter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
private void btncutter_click( object sender,eventargs e)
{
//新建一个和屏幕大小相同的图片img 也可以用bitmap
image img= new bitmap(screen.allscreens[0].bounds.width,screen.allscreens[0].bounds.height);
//创建一个画板 让我们可以在画板上画图 大小和屏幕大小一样大
graphics g=graphics.fromimage(img);
//将屏幕图片拷贝到空白图片img
g.copyfromscreen( new point(0,0), new point(0,0),screen.allscreens[0].bounds.size);
//创建截图窗体
screenbody body=screenbody.getsingle();
//指示窗体的背景图片为屏幕图片
body.backgroundimage=img;
body.showdialog();
}
|
对于窗体screenbody
声明全局变量
1
2
3
4
5
|
private bool catchstart; //判断鼠标是否按下
private bool catchfinished; //判断矩形是否绘制完成
private point downpoint; //鼠标按下的点
private image basemap; //最基本的图片
private rectangle catchrectangle;
|
必须要实现的那几个事件
鼠标按下mousedown
1
2
3
4
5
6
7
8
9
10
11
12
13
|
private void screenbody_mousedown( object sender, mouseeventargs e)
{
//鼠标左键按下就是开始画图,也就是截图
if (e.button == mousebuttons.left)
{
if (catchstart == false )
{
catchstart = true ;
//保存此时的坐标
downpoint = new point(e.x, e.y);
}
}
}
|
鼠标移动 mousemove
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
|
private void screenbody_mousemove( object sender, mouseeventargs e)
{
//确保截图开始
if (catchstart)
{
//新建一个图片,让它与屏幕图片相同
bitmap copybmp = (bitmap)basemap.clone();
//鼠标按下时的坐标
point newpoint = new point(downpoint.x, downpoint.y);
//新建画板和画笔
graphics g = graphics.fromimage(copybmp);
pen p = new pen(color.azure, 1); //画笔的颜色为azure 宽度为1
//获取矩形的长度
int width = math.abs(e.x - downpoint.y);
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();
}
|
鼠标弹起 mouseup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/// <summary>
/// 鼠标左键弹起事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void screenbody_mouseup( object sender, mouseeventargs e)
{
if (e.button == mousebuttons.left)
{
//如果截图已经开始,鼠标左键弹起设置截图完成
if (catchstart)
{
catchstart = false ;
catchfinished = true ;
}
}
}
|
鼠标双击
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
|
private void screenbody_mousedoubleclick( object sender, mouseeventargs e)
{
if (e.button==mousebuttons.left&&catchfinished)
{
//新建一个矩形大小相同的空白图片
bitmap catchebmp = new bitmap(catchrectangle.width, catchrectangle.height);
graphics g = graphics.fromimage(catchebmp); ;
//把basemap中指定的部分按照指定大小画到空白图片上
//catchrectangle指定的basemap中指定的部分
//第二个参数指定绘制到空白图片的位置和大小
//画完后catchedbmp不再是空白图片,而是具有与截取的图片一样的内容
g.drawimage(basemap, new rectangle(0, 0, catchrectangle.width, catchrectangle.height));
//将图片保存到剪切板中
clipboard.setimage(catchebmp);
g.dispose();
catchfinished = false ;
this .backgroundimage = basemap;
catchebmp.dispose();
this .dialogresult = dialogresult.ok;
this .close();
}
}
|
鼠标右键 退出截图
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/// <summary>
/// 鼠标右键点击结束截图
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void screenbody_mouseclick( object sender, mouseeventargs e)
{
if (e.button == mousebuttons.right)
{
this .dialogresult = dialogresult.ok;
this .close();
}
}
|
最复杂的热键注册 自己也是去网上看的 main窗体中
声明枚举
1
2
3
4
5
6
7
8
9
|
[flagsattribute]
public enum keymodifiers
{
none = 0,
alt = 1,
ctrl = 2,
shift = 4,
windowskey = 8
}
|
然后在类中编辑一下代码
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
|
//在c#中引用命名空间system.runtime.interopservices;来加载非托管类user32.dll
/*
* registerhotkey函数原型及说明:
* bool registerhotkey(
* hwnd hwnd, // window to receive hot-key notification
* int id, // identifier of hot key
* uint fsmodifiers, // key-modifier flags
* uint vk // virtual-key code);
* 参数 id为你自己定义的一个id值
* 对一个线程来讲其值必需在0x0000 - 0xbfff范围之内,十进制为0~49151
* 对dll来讲其值必需在0xc000 - 0xffff 范围之内,十进制为49152~65535
* 在同一进程内该值必须唯一参数 fsmodifiers指明与热键联合使用按键
* 可取值为:mod_alt mod_control mod_win mod_shift参数,或数字0为无,1为alt,2为control,4为shift,8为windows
* vk指明热键的虚拟键码
*/
[system.runtime.interopservices.dllimport( "user32.dll" )] //申明api函数
public static extern bool registerhotkey(
intptr hwnd, // handle to window
int id, // hot key identifier
uint fsmodifiers, // key-modifier options
keys vk // virtual-key code
);
[system.runtime.interopservices.dllimport( "user32.dll" )] //申明api函数
public static extern bool unregisterhotkey(
intptr hwnd, // handle to window
int id // hot key identifier
);
|
再接着
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
|
private void form1_load( object sender, eventargs e)
{
uint ctrlhotkey = ( uint )(keymodifiers.alt | keymodifiers.ctrl);
// 注册热键为alt+ctrl+c, "100"为唯一标识热键
registerhotkey(handle, 100, ctrlhotkey, keys.a);
}
//热键按下执行的方法
private void globalkeyprocess()
{
this .windowstate = formwindowstate.minimized;
//窗口最小化需要一定的时间 使用线程
thread.sleep(200);
btncutter.performclick();
}
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 ;
default :
break ;
}
base .wndproc( ref m);
}
private void form1_formclosing( object sender, formclosingeventargs e)
{
// 卸载热键
unregisterhotkey(handle, 100);
}
|
热键的功能就能实现。但是我遇到了很多问题 首先是basemap 没有初始化值
这些问题 还有待解决!!!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://www.cnblogs.com/Audient/p/7684922.html