1、概述
截图是一个非常常见的功能。但是Windows自带的截图功能我们发现并不好用。所以很多时候我们打开QQ就是为了做一个截图。QQ的截图功能还是非常强大的,今天,我将用Qt4手工做一个简单的截图。这个截图比不上QQ的截图,只实现了基本功能。没有复杂的操作,供大家学习、参考。
2、 需求描述
最终成品是一个可执行的exe文件,运行平台是Windows操作系统(经过我的测试,在Windows7、10下均可以完美运行)。
打开软件后,屏幕变暗,进入“自由模式”,在这个模式下,鼠标可以自由移动。自由模式可以做以下的事情:
- 自由模式上面显示一个图片表示当前位于自由模式下,鼠标左键单击图片,图片会消失。
- 单击鼠标左键,开始抓图,进入“截屏模式”,上面的图片自动消失。在这个模式下,鼠标按住拖动会产生一个橡皮框。表示要截图的区域。橡皮框左上角会产生一个QLabel指示这个橡皮框的大小(像素)。
- 松开鼠标后,程序会询问用户是否要保存图片,如果用户选择“yes”,那么会弹出一个保存文件的对话框,图片只能保存为png格式的。程序这时候会抓取橡皮框区域的图片,保存并且退出。如果用户选择“no”,橡皮框和QLabel均消失。
- 在自由模式下双击鼠标左键自动截取全屏。
- 在自由模式下单击鼠标右键不截图,直接退出程序。
3、软件截图
自由模式:
截图模式:
询问用户:
3、 开发环境
本软件采用Qt 4.8.7 开发,操作系统为Windows10 64位。没有使用QtDesigner、QtCreator。
编译环境为mingw32 4.8.2
4、 分析
注意:下面只分析和截图功能有关的代码,很多细枝末节(如图片提示、文件保存)代码不再解释。
要想实现这个程序,思路其实很简单。我们只要获取当前整个桌面的图片,把这个图片设置为主窗口的背景图片。然后让主窗口充斥整个桌面。
获取整个桌面并不难,Qt是有直接提供实现的。我们看QPixmap的如下成员函数:
QPixmap grabWindow ( WId window, int x = 0, int y = 0, int width = -1, int height = -1 )
关心第一个参数,它表示要截取的Window ID。这里我们要截取整个桌面,使用QApplication::desktop()->winId()即可。后面的参数不需要关心,默认它就是截取整个窗口的。
我们只需要把主窗口的背景设置为这个图片,大小设置为图片的大小。还需要把主窗口的状态栏隐藏,实现也很简单,利用setWindowFlags()设置Qt::FramelessWindowHint即可。
获取整个桌面的QPixmap以后,我们需要两份副本。一份用来变暗并显示在主窗口上,另外一份是原本,用于稍后真正的截图。
一个懊恼的问题是我们如何把图片变暗。我找了很多方法,这里采用一个简单的:把图片的三原色全部乘以一个倍数。注意,QPixmap并没有获取三原色的方法,所以我只好把QPixmap转换为QImage。这里我使用了一个中间文件temp.png。效率略低,有更好方法的小伙伴欢迎评论。
whole_window.save("temp.png");
bg = QImage("temp.png");
QFile *temp = new QFile("temp.png");
temp->remove();
whole_window表示用grabWindow抓取的QPixmap,bg是一个QImage类对象,它们都是主窗口类的成员。
接着,使用以下手段使QImage变暗:
int red,green,blue;
for(int i = x; i < width; i++){
for(int j = y; j < height; j++){
//三原色全部乘以一个倍数,实现屏幕的变暗
red = qRed(bg.pixel(i, j)) * bright ;
green = qGreen(bg.pixel(i, j)) * bright;
blue = qBlue(bg.pixel(i, j)) * bright;
bg.setPixel( i, j, qRgb(red, green, blue));
}
}
然后我们重写paintEvent事件把bg设置为主窗口的背景图片:
void screenShot::paintEvent(QPaintEvent *event){
QPainter painter(this);
//把bg设置为整个窗口的背景图片
painter.drawImage(0, 0, bg);
}
这就实现了点开程序,整个桌面变暗的假象了。
接下来,整个程序的关键来了:在用户点击鼠标左键的时候,我们需要开始抓