您的位置:首页 > 编程语言 > Qt开发

QT实现截屏功能

2015-05-28 11:59 253 查看
QT实现截屏功能 2011-05-18
17:27:57

分类: C/C++

最近因为需要开发一个类似QQ的截屏功能,花了不少的时间,开始的时候很多也不懂,不知道如何下手,在网上找了很多的资料,现已经实现了截屏,移动截屏选区,通过拖动选区的八个控制点来改变选区的大小。
QT实现截屏的原理是,当点击截屏按钮(菜单栏上的截屏按钮)时,调用fullScreenWidget对象getFullScreenPixmap()方法,返回当前屏幕的QPixmap图片对象。在构造调用窗体的构造函数中,关联信号与槽,使其在点击“截屏”按钮发送信息给fullScreenWidget对象对应的槽函数,以便加载当前的背景图片。

connect(newAct,SIGNAL(triggered()),this,SLOT(screenshot()));
connect(this,SIGNAL(setPixmap(QPixmap)),fullWidget,SLOT(loadBackgroundPixmap(QPixmap)));

在fullScreenWidget类中,主要是根据当前截屏的状态来实时的判断如果截取屏幕。我在类中定义了shotState枚举类型,用来判断当前截屏的状态。定义了QPoint beginPoint,endPoint,moveBeginPoint,moveEndPoint;四个对象主要用来记录开始,结束的截屏坐标。移动的开始,结束坐标。根据不同的截屏状态和这4个坐标点的值来计算截屏的区域。我的表达能力不太好,先把核心代码上面来。fullScreenWidget.h头文件代码如下:

#ifndef FULLSCREENWIDGET_H

#define FULLSCREENWIDGET_H

#include <QWidget>

#include <QPixmap>

#include <QPoint>

#include <QtGui>

#include <QPainter>

#include <QBrush>

class fullScreenWidget : public QWidget{

Q_OBJECT

public:

fullScreenWidget(); //构造函数

enum shotState{initShot,beginShot,finishShot,endShot,beginMoveShot,finishMoveShot,beginControl,finishControl}; //进行截屏的状态

//移动选区中的8个控制点,按照顺时针方向从左上控制点到左中控制点分配编号为1~8

enum controlPointEnum{moveControl0,moveControl1,moveControl2,moveControl3,moveControl4,moveControl5,moveControl6,moveControl7,moveControl8};

QPixmap getFullScreenPixmap(); //获取全屏的Pixmap

public slots:

void loadBackgroundPixmap(const QPixmap &bgPixmap);//加载背景Pixmap槽函数

void loadBackgroundPixmap(const QPixmap &bgPixmap, int x, int y, int width, int height); //加载背景pixmap槽函数,设置x,y,width,height

void cancelSelectedRect(); //取消选择区域

void savePixmap(); //保选取行为的方法

signals:

void finishPixmap(const QPixmap &finishPixmap); //完成切图后的图片,发送信号给连接者

private:

//选区框的8个点选取

QRect tlRect; //左上点

QRect trRect; //右上点

QRect blRect; //左下点

QRect brRect; //右下点

QRect tcRect; //上中点

QRect bcRect; //下中点

QRect lcRect;//左中点

QRect rcRect; //右中点

QPainter painter;

QPoint beginPoint,endPoint,moveBeginPoint,moveEndPoint;

QRect selectedRect; //选择区域

QPixmap loadPixmap,shotPixmap;

shotState currentShotState; //当前的截屏状态

controlPointEnum controlValue; //记录移动控制点的值

QAction *savePixmapAction; //保存图片行为

QAction *cancelAction; //取消选取行为

QAction *quitAction; //退出选取行为

QMenu *contextMenu; //选中区域右键菜单

int screenwidth; //整个屏幕的宽度

int screenheight; //整个屏幕的高度

int screenx; //选区的X

int screeny; //选区的Y

int tipWidth,tipHeight,infoWidth,infoHeight; //加载初始框的宽度,高度;显示坐标信息的宽度,高度

QRect getSelectedRect(); //获取选取

QRect getRect(const QPoint &beginPoint, const QPoint &endPoint); //根据两个点获取选取坐标

void initFullScreenWidget(); //初始化抓全屏的相关参数

bool isInSelectedRect(const QPoint &point); //判断该点是否在选中区域

void initSelectedMenu();//初始化右键菜单

void drawTipsText(); //在屏幕上打印提示信息

void drawSelectedPixmap(void); //在屏幕上画选取的屏幕

void updateBeginEndPointValue(const QRect &rect); //当移动选取后,对beginPoint,endPoint坐标进行重新修改

void checkMoveEndPoint(); //对移动的选区进行判断

void draw8ControlPoint(const QRect &rect);

void updateMouseShape(const QPoint &point); //更新鼠标的当前状态

void updateMoveControlMouseShape(controlPointEnum controlValue);

controlPointEnum getMoveControlState(const QPoint &point); //获取移动控制点状态

QRect getMoveAllSelectedRect(void); //获取移动整个选中的选区

QRect getMoveControlSelectedRect(void);//获取移动控制点的选区

int getMinValue(int num1, int num2);//获取两个数中的最小值

void drawXYWHInfo(void); //打印选取的x,y,h,w值信息

//重写基类方法

void keyPressEvent(QKeyEvent *event);

void paintEvent(QPaintEvent *event);

void mousePressEvent(QMouseEvent *event);

void mouseReleaseEvent(QMouseEvent *event);

void mouseMoveEvent(QMouseEvent *event);

void mouseDoubleClickEvent(QMouseEvent *event);

void contextMenuEvent(QContextMenuEvent *event);

};

#endif

fullScreenWidget.cpp类的实现文件如下:

#include "fullScreenWidget.h"

fullScreenWidget::fullScreenWidget()

{

setWindowState(Qt::WindowActive|Qt::WindowFullScreen);

tipWidth = 300; //温馨提示框的宽度

tipHeight = 100; //温馨提示框的高度

infoWidth = 100; //坐标信息框的宽度

infoHeight = 50; //坐标信息框的高度

initFullScreenWidget();

}

void fullScreenWidget::initSelectedMenu()

{

savePixmapAction = new QAction(tr("保存选区"),this);

cancelAction = new QAction(tr("重选"),this);

quitAction = new QAction(tr("退出"),this);

contextMenu = new QMenu(this);

connect(savePixmapAction,SIGNAL(triggered()),this,SLOT(savePixmap()));

connect(cancelAction,SIGNAL(triggered()),this,SLOT(cancelSelectedRect()));

connect(quitAction,SIGNAL(triggered()),this,SLOT(hide()));

}

void fullScreenWidget::savePixmap()

{

QString fileName;

fileName = QFileDialog::getSaveFileName(this,tr("保存图片"),QDir::currentPath(),tr("Images
(*.jpg *.png *.bmp)"));

if(fileName.isNull())

return;

shotPixmap.save(fileName);

hide();

}

void fullScreenWidget::loadBackgroundPixmap(const QPixmap &bgPixmap)

{

int width,height;

width = QApplication::desktop()->size().width();

height = QApplication::desktop()->size().height();

loadBackgroundPixmap(bgPixmap,0,0,width,height);

}

void fullScreenWidget::loadBackgroundPixmap(const QPixmap &bgPixmap, int x, int y, int width, int height)

{

loadPixmap = bgPixmap;

screenx = x;

screeny = y;

screenwidth = width;

screenheight = height;

initFullScreenWidget();

}

QPixmap fullScreenWidget::getFullScreenPixmap()

{

initFullScreenWidget();

QPixmap result = QPixmap();

result = QPixmap::grabWindow(QApplication::desktop()->winId()); //抓取当前屏幕的图片

return result;

}

void fullScreenWidget::paintEvent(QPaintEvent *event)

{

QColor shadowColor;

shadowColor= QColor(0,0,0,100); //阴影颜色设置

painter.begin(this); //进行重绘

painter.setPen(QPen(Qt::blue,2,Qt::SolidLine,Qt::FlatCap));//设置画笔

painter.drawPixmap(screenx,screeny,loadPixmap); //将背景图片画到窗体上

painter.fillRect(screenx,screeny,screenwidth,screenheight,shadowColor); //画影罩效果

switch(currentShotState){

case initShot:

drawTipsText();

break;

case beginShot:

case finishShot:

selectedRect = getRect(beginPoint,endPoint); //获取选区

drawSelectedPixmap();

break;

case beginMoveShot:

case finishMoveShot:

selectedRect = getMoveAllSelectedRect(); //获取选区

drawSelectedPixmap();

break;

case beginControl:

case finishControl:

selectedRect = getMoveControlSelectedRect();

drawSelectedPixmap();

break;

default:

break;

}

drawXYWHInfo(); //打印坐标信息

painter.end(); //重绘结束

if(currentShotState == finishMoveShot || currentShotState == finishControl){

updateBeginEndPointValue(selectedRect); //当移动完选区后,更新beginPoint,endPoint;为下一次移动做准备工作

}

}

void fullScreenWidget::keyPressEvent(QKeyEvent *event)

{

if(event->key() == Qt::Key_Escape){

initFullScreenWidget();

hide();

}

}

void fullScreenWidget::mousePressEvent(QMouseEvent *event)

{

//当开始进行拖动进行选择区域时,确定开始选取的beginPoint坐标

if(event->button() == Qt::LeftButton && currentShotState == initShot){

currentShotState = beginShot; //设置当前状态为beginShot状态

beginPoint = event->pos();

}

//移动选区改变选区的所在位置

if(event->button() == Qt::LeftButton && isInSelectedRect(event->pos()) &&

getMoveControlState(event->pos()) == moveControl0){

currentShotState = beginMoveShot; //启用开始移动选取选项,beginMoveShot状态

moveBeginPoint = event->pos();

}

//移动控制点改变选区大小

if(event->button() == Qt::LeftButton && getMoveControlState(event->pos()) != moveControl0){

currentShotState = beginControl; //开始移动控制点

controlValue = getMoveControlState(event->pos());

moveBeginPoint = event->pos();

}

}

void fullScreenWidget::mouseReleaseEvent(QMouseEvent *event)

{

if(event->button() == Qt::LeftButton && currentShotState == beginShot){

currentShotState = finishShot;

endPoint = event->pos();

update();

}

if(event->button() == Qt::LeftButton && currentShotState == beginMoveShot){

currentShotState = finishMoveShot;

moveEndPoint = event->pos();

update();

}

//当前状态为beginControl状态时,设置状态为finishControl

if(event->button() == Qt::LeftButton && currentShotState == beginControl){

currentShotState = finishControl;

moveEndPoint = event->pos();

update();

}

}

void fullScreenWidget::mouseMoveEvent(QMouseEvent *event)

{

//当拖动时,动态的更新所选择的区域

if(currentShotState == beginShot){

endPoint = event->pos();

update();

}

//当确定选区后,对选区进行移动操作

if(currentShotState == beginMoveShot || currentShotState == beginControl){

moveEndPoint = event->pos();

update();

}

updateMouseShape(event->pos()); //修改鼠标的形状

setMouseTracking(true);

}

void fullScreenWidget::mouseDoubleClickEvent(QMouseEvent *event)

{

if(currentShotState == finishShot || currentShotState == finishMoveShot || currentShotState == finishControl){

emit finishPixmap(shotPixmap); //当完成时发送finishPixmap信号

hide();

}

}

QRect fullScreenWidget::getRect(const QPoint &beginPoint, const QPoint &endPoint)

{

int x,y,width,height;

width = qAbs(beginPoint.x() - endPoint.x());

height = qAbs(beginPoint.y() - endPoint.y());

x = beginPoint.x() < endPoint.x() ? beginPoint.x() : endPoint.x();

y = beginPoint.y() < endPoint.y() ? beginPoint.y() : endPoint.y();

return QRect(x,y,width,height);

}

void fullScreenWidget::initFullScreenWidget()

{

currentShotState = initShot;

controlValue = moveControl0;

beginPoint =QPoint(0,0);

endPoint = QPoint(0,0);

moveBeginPoint = QPoint(0,0);

moveEndPoint = QPoint(0,0);

tlRect = QRect(0,0,0,0); //左上点

trRect = QRect(0,0,0,0); //上右点

blRect = QRect(0,0,0,0); //左下点

brRect = QRect(0,0,0,0); //右下点

tcRect = QRect(0,0,0,0); //上中点

bcRect = QRect(0,0,0,0); //下中点

lcRect = QRect(0,0,0,0); //左中点

rcRect = QRect(0,0,0,0); //右中点

setCursor(Qt::CrossCursor);

}

bool fullScreenWidget::isInSelectedRect(const QPoint &point)

{

int x,y;

QRect selectedRect;

if(currentShotState == initShot || currentShotState == beginShot)

return false;

selectedRect = getSelectedRect();

x = point.x();

y = point.y();

return selectedRect.contains(x,y);

}

void fullScreenWidget::cancelSelectedRect()

{

initFullScreenWidget();

update(); //进行重绘,将选取区域去掉

}

void fullScreenWidget::contextMenuEvent(QContextMenuEvent *event)

{

initSelectedMenu();

if(isInSelectedRect(event->pos())){

contextMenu->addAction(savePixmapAction);

}

else{

contextMenu->addAction(cancelAction);

contextMenu->addAction(quitAction);

}

contextMenu->exec(event->pos());

}

void fullScreenWidget::drawTipsText()

{

int x = (screenwidth - tipWidth)/2;

int y = (screenheight - tipHeight)/2;

QColor color = QColor(100,100,100,200);

QRect rect = QRect(x,y,tipWidth,tipHeight);

QString strTipsText = QString(tr("温馨提示\n鼠标拖动进行截屏;截屏区域内右键保存;\n截屏区域外右键取消;ESC退出;"));

painter.fillRect(rect,color);

painter.setPen(QPen(Qt::white));//设置画笔的颜色为白色

painter.drawText(rect,Qt::AlignCenter,strTipsText);

}

QRect fullScreenWidget::getSelectedRect()

{

if(currentShotState == beginMoveShot){

return getMoveAllSelectedRect();

}

else if(currentShotState == beginControl){

return getMoveControlSelectedRect();

}

else{

return getRect(beginPoint,endPoint);

}

}

void fullScreenWidget::updateBeginEndPointValue(const QRect &rect)

{

beginPoint = rect.topLeft();

endPoint = rect.bottomRight();

moveBeginPoint = QPoint(0,0);

moveEndPoint = QPoint(0,0);

}

void fullScreenWidget::checkMoveEndPoint()

{

int x,y;

QRect selectedRect = getRect(beginPoint, endPoint);

QPoint bottomRightPoint = selectedRect.bottomRight();

x = moveEndPoint.x() - moveBeginPoint.x();

y = moveEndPoint.y() - moveBeginPoint.y();

if(x + selectedRect.x() < 0){ //当移动后X坐标小于零时,则出现选区丢失,则计算出moveEndPoint的X最大坐标值,进行赋值

moveEndPoint.setX(qAbs(selectedRect.x()-moveBeginPoint.x()));

}

if(y + selectedRect.y() < 0){ //当移动后Y坐标小于零时,则出现选区丢失,则计算出moveEndPoint的Y最大坐标值,进行赋值

moveEndPoint.setY(qAbs(selectedRect.y() - moveBeginPoint.y()));

}

if(x + bottomRightPoint.x() > screenwidth){ //当移动选区后,出现超出整个屏幕的右面时,设置moveEndPoint的X的最大坐标

moveEndPoint.setX(screenwidth - bottomRightPoint.x() + moveBeginPoint.x());

}

if(y + bottomRightPoint.y() > screenheight){ //当移动选区后,出现超出整个屏幕的下面时,设置moveEndPoint的Y的最大坐标值

moveEndPoint.setY(screenheight - bottomRightPoint.y() + moveBeginPoint.y());

}

}

void fullScreenWidget::draw8ControlPoint(const QRect &rect)

{

int x,y;

QColor color= QColor(0,0,255); //画点的颜色设置

QPoint tlPoint = rect.topLeft(); //左上点

QPoint trPoint = rect.topRight(); //右上点

QPoint blPoint = rect.bottomLeft(); //左下点

QPoint brPoint = rect.bottomRight(); //右下点

x = (tlPoint.x()+trPoint.x())/2;

y = tlPoint.y();

QPoint tcPoint = QPoint(x,y);

x = (blPoint.x()+brPoint.x())/2;

y = blPoint.y();

QPoint bcPoint = QPoint(x,y);

x = tlPoint.x();

y = (tlPoint.y()+blPoint.y())/2;

QPoint lcPoint = QPoint(x,y);

x = trPoint.x();

y = (trPoint.y()+brPoint.y())/2;

QPoint rcPoint = QPoint(x,y);

tlRect = QRect(tlPoint.x()-2,tlPoint.y()-2,6,6); //左上点

trRect = QRect(trPoint.x()-2,trPoint.y()-2,6,6); //右上点

blRect = QRect(blPoint.x()-2,blPoint.y()-2,6,6); //左下点

brRect = QRect(brPoint.x()-2,brPoint.y()-2,6,6); //右下点

tcRect = QRect(tcPoint.x()-2,tcPoint.y()-2,6,6); //上中点

bcRect = QRect(bcPoint.x()-2,bcPoint.y()-2,6,6); //下中点

lcRect = QRect(lcPoint.x()-2,lcPoint.y()-2,6,6);//左中点

rcRect = QRect(rcPoint.x()-2,rcPoint.y()-2,6,6); //右中点

painter.fillRect(tlRect,color);

painter.fillRect(trRect,color);

painter.fillRect(blRect,color);

painter.fillRect(brRect,color);

painter.fillRect(tcRect,color);

painter.fillRect(bcRect,color);

painter.fillRect(lcRect,color);

painter.fillRect(rcRect,color);

}

void fullScreenWidget::updateMouseShape(const QPoint &point)

{

switch(currentShotState){

case initShot:

case beginShot:

setCursor(Qt::CrossCursor);

break;

case beginMoveShot:

setCursor(Qt::OpenHandCursor);

break;

case finishShot:

case finishMoveShot:

case finishControl:

if(getSelectedRect().contains(point))

setCursor(Qt::OpenHandCursor);

else

updateMoveControlMouseShape(getMoveControlState(point));

break;

case beginControl:

updateMoveControlMouseShape(controlValue); //调用函数对移动8个控制点进行鼠标状态的改变

break;

default:

setCursor(Qt::ArrowCursor);

break;

}

}

void fullScreenWidget::updateMoveControlMouseShape(controlPointEnum controlValue){

switch(controlValue){

case moveControl1:

case moveControl5:

setCursor(Qt::SizeFDiagCursor);

break;

case moveControl2:

case moveControl6:

setCursor(Qt::SizeVerCursor);

break;

case moveControl3:

case moveControl7:

setCursor(Qt::SizeBDiagCursor);

break;

case moveControl4:

case moveControl8:

setCursor(Qt::SizeHorCursor);

break;

default:

setCursor(Qt::ArrowCursor);

break;

}

}

fullScreenWidget::controlPointEnum fullScreenWidget::getMoveControlState(const QPoint &point)

{

fullScreenWidget::controlPointEnum result = moveControl0;

if(currentShotState == initShot || currentShotState == beginShot) {

result = moveControl0;

}

else if(tlRect.contains(point)){

result = moveControl1;

}

else if(tcRect.contains(point)){

result = moveControl2;

}

else if(trRect.contains(point)){

result = moveControl3;

}

else if(rcRect.contains(point)){

result = moveControl4;

}

else if(brRect.contains(point)){

result = moveControl5;

}

else if(bcRect.contains(point)){

result = moveControl6;

}

else if(blRect.contains(point)){

result = moveControl7;

}

else if(lcRect.contains(point)){

result = moveControl8;

}

else{

result = moveControl0;

}

return result;

}

QRect fullScreenWidget::getMoveAllSelectedRect(void)

{

QRect result;

QPoint tmpBeginPoint,tmpEndPoint;

int moveX,moveY;

checkMoveEndPoint(); //对移动选区进行判断,当移动的选区超出边界,则停止移动

moveX = moveEndPoint.x() - moveBeginPoint.x();

moveY = moveEndPoint.y() - moveBeginPoint.y();

tmpBeginPoint.setX(beginPoint.x() + moveX);

tmpBeginPoint.setY(beginPoint.y() + moveY);

tmpEndPoint.setX(endPoint.x() + moveX);

tmpEndPoint.setY(endPoint.y() + moveY);

result = getRect(tmpBeginPoint, tmpEndPoint);

return result;

}

QRect fullScreenWidget::getMoveControlSelectedRect(void)

{

int x,y,w,h;

QRect rect = getRect(beginPoint,endPoint);

QRect result;

switch(controlValue){

case moveControl1:

result = getRect(rect.bottomRight(),moveEndPoint);

return result;

break;

case moveControl2:

x = rect.x();

y = getMinValue(moveEndPoint.y(),rect.bottomLeft().y());

w = rect.width();

h = qAbs(moveEndPoint.y() - rect.bottomRight().y());

break;

case moveControl3:

result = getRect(rect.bottomLeft(),moveEndPoint);

return result;

break;

case moveControl4:

x = getMinValue(rect.x(),moveEndPoint.x());

y = rect.y();

w = qAbs(rect.bottomLeft().x() - moveEndPoint.x());

h = rect.height();

break;

case moveControl5:

result = getRect(rect.topLeft(),moveEndPoint);

return result;

break;

case moveControl6:

x = rect.x();

y = getMinValue(rect.y(),moveEndPoint.y());

w = rect.width();

h = qAbs(moveEndPoint.y() - rect.topLeft().y());

break;

case moveControl7:

result = getRect(moveEndPoint,rect.topRight());

return result;

break;

case moveControl8:

x = getMinValue(moveEndPoint.x(),rect.bottomRight().x());

y = rect.y();

w = qAbs(rect.bottomRight().x() - moveEndPoint.x());

h = rect.height();

break;

default:

result = getRect(beginPoint,endPoint);

return result;

break;

}

return QRect(x,y,w,h); //获取选区

}

int fullScreenWidget::getMinValue(int num1, int num2)

{

return num1<num2?num1:num2;

}

void fullScreenWidget::drawSelectedPixmap(void)

{

painter.drawRect(selectedRect); //画选中的矩形框

shotPixmap = loadPixmap.copy(selectedRect); //更新选区的Pixmap

if(selectedRect.width() > 0 && selectedRect.height()){

painter.drawPixmap(selectedRect.topLeft(),shotPixmap); //画选中区域的图片

}

draw8ControlPoint(selectedRect); //画出选区的8个控制点

}

void fullScreenWidget::drawXYWHInfo(void)

{

int x,y;

QColor color = QColor(239,234,228,200);

QRect rect;

QString strTipsText;

switch(currentShotState){

case beginShot:

case finishShot:

case beginMoveShot:

case finishMoveShot:

case beginControl:

case finishControl:

x = selectedRect.x() + 5;

y = selectedRect.y() > infoHeight ? selectedRect.y()-infoHeight:selectedRect.y();

rect = QRect(x,y,infoWidth,infoHeight);

strTipsText = QString(tr("
坐标信息\n x:%1 y:%2\n w:%3 h:%4")).arg(selectedRect.x(),4).arg(selectedRect.y(),4)

.arg(selectedRect.width(),4).arg(selectedRect.height(),4);

painter.fillRect(rect,color);

painter.setPen(QPen(Qt::black));//设置画笔的颜色为黑色

painter.drawText(rect,Qt::AlignLeft|Qt::AlignVCenter,strTipsText);

break;

default:

break;

}

}



screenshot.zip

您可以下载下来,进行测试使用。解压文件后,使用qtcreator工具进行加载screenshot.pro文件。执行qmake,build,run。即可。
注:因我提供的源代码在ubuntu操作系统上编写,如果您使用的是windows操作系统,可能需要qtcreator修改字符集为uft-8即可。本代码使用的是qt4.6.2进行编译,使用emacs编辑器进行编写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: