Qt實現擷取螢幕小程式
阿新 • • 發佈:2019-01-26
[注]:本程式在Windows下實現,按理來說在其他平臺也可用(只需要改一下CCuter的某個函式,文中紅字標註)
先上效果圖(我兩個顯示屏整張圖太大,只截關鍵部分上傳):
以下是程式碼,兩個部分:一個是CCuter截圖選擇器,一個是CScreenShoot截圖程式
CCuter.h
#ifndef CCUTER_H #define CCUTER_H #include <QWidget> //* 截圖選擇器 class CCuter: public QWidget { Q_OBJECT public: CCuter(); signals: void cut (); //* 截圖 void cancle(); //* 取消 protected: int mTouchBorderWidth; bool mMousePressed; QPoint mLastMouseMovePos; int mCurrentHit; void mousePressEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e); int OnNcHitTest(MSG* msg); //* 檢測滑鼠狀態並嘗試改變大小(native window) int OnNcHitTest(QPoint pos); //* 檢測滑鼠狀態並嘗試改變大小(software method,without native window) void contextMenuEvent(QContextMenuEvent *e); //* 支援的選單項 }; #endif // CCUTER_H
[注]:如果是在windows以外的平臺需要修改OnNcHitTest函式的實現。
CCuter.cpp
#include "CCuter.h" #include <QPainter> #include <QPainterPath> #include <QMouseEvent> #include <QMenu> #include <QDebug> #include <Windows.h> #include <WindowsX.h> CCuter::CCuter() :mTouchBorderWidth(10) ,mMousePressed(false) ,mCurrentHit(HTCLIENT) { this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Widget); this->setAttribute(Qt::WA_TranslucentBackground); this->setMouseTracking(true); this->setCursor(Qt::OpenHandCursor); this->setContextMenuPolicy(Qt::DefaultContextMenu); } void CCuter::mousePressEvent(QMouseEvent *e) { QWidget::mousePressEvent(e); mMousePressed = true; mLastMouseMovePos = e->globalPos(); } void CCuter::mouseReleaseEvent(QMouseEvent *e) { QWidget::mouseReleaseEvent(e); mMousePressed = false; //TODO:Cursor if(!mMousePressed) { switch(mCurrentHit) { case HTLEFT: this->setCursor(Qt::SizeHorCursor); break; case HTRIGHT: this->setCursor(Qt::SizeHorCursor); break; case HTTOP: this->setCursor(Qt::SizeVerCursor); break; case HTBOTTOM: this->setCursor(Qt::SizeVerCursor); break; case HTTOPLEFT: this->setCursor(Qt::SizeFDiagCursor); break; case HTTOPRIGHT: this->setCursor(Qt::SizeBDiagCursor); break; case HTBOTTOMLEFT: this->setCursor(Qt::SizeBDiagCursor); break; case HTBOTTOMRIGHT: this->setCursor(Qt::SizeFDiagCursor); break; case HTCLIENT: this->setCursor(Qt::OpenHandCursor); break; } } } void CCuter::mouseMoveEvent(QMouseEvent *e) { QPoint currentPos = e->globalPos(); QPoint defPos = currentPos - mLastMouseMovePos; mLastMouseMovePos = e->globalPos(); //TODO:Cursor if(!mMousePressed) { mCurrentHit = OnNcHitTest(e->pos()); switch(mCurrentHit) { case HTLEFT: this->setCursor(Qt::SizeHorCursor); break; case HTRIGHT: this->setCursor(Qt::SizeHorCursor); break; case HTTOP: this->setCursor(Qt::SizeVerCursor); break; case HTBOTTOM: this->setCursor(Qt::SizeVerCursor); break; case HTTOPLEFT: this->setCursor(Qt::SizeFDiagCursor); break; case HTTOPRIGHT: this->setCursor(Qt::SizeBDiagCursor); break; case HTBOTTOMLEFT: this->setCursor(Qt::SizeBDiagCursor); break; case HTBOTTOMRIGHT: this->setCursor(Qt::SizeFDiagCursor); break; case HTCLIENT: this->setCursor(Qt::OpenHandCursor); break; } } else { QRect resizeRect = this->geometry(); switch(mCurrentHit) { case HTLEFT: resizeRect.setLeft(currentPos.x()); break; case HTRIGHT: resizeRect.setRight(currentPos.x()); break; case HTTOP: resizeRect.setTop(currentPos.y()); break; case HTBOTTOM: resizeRect.setBottom(currentPos.y()); break; case HTTOPLEFT: resizeRect.setTopLeft(currentPos); break; case HTTOPRIGHT: resizeRect.setTopRight(currentPos); break; case HTBOTTOMLEFT: resizeRect.setBottomLeft(currentPos); break; case HTBOTTOMRIGHT: resizeRect.setBottomRight(currentPos); break; case HTCLIENT: this->move(this->pos() + defPos); break; } if(mCurrentHit != HTCLIENT) { if(resizeRect.left() > resizeRect.right()) { int t = resizeRect.left(); resizeRect.setLeft(resizeRect.right()); resizeRect.setRight(t); switch(mCurrentHit) { case HTLEFT: mCurrentHit = HTRIGHT; break; case HTRIGHT: mCurrentHit = HTLEFT; break; case HTTOP: break; case HTBOTTOM: break; case HTTOPLEFT: mCurrentHit = HTTOPRIGHT; break; case HTTOPRIGHT: mCurrentHit = HTTOPLEFT; break; case HTBOTTOMLEFT: mCurrentHit = HTBOTTOMRIGHT; break; case HTBOTTOMRIGHT: mCurrentHit = HTBOTTOMLEFT; break; case HTCLIENT: break; } } if(resizeRect.top() > resizeRect.bottom()) { int t = resizeRect.top(); resizeRect.setTop(resizeRect.bottom()); resizeRect.setBottom(t); switch(mCurrentHit) { case HTLEFT: break; case HTRIGHT: break; case HTTOP: mCurrentHit = HTBOTTOM; break; case HTBOTTOM: mCurrentHit = HTTOP; break; case HTTOPLEFT: mCurrentHit = HTBOTTOMLEFT; break; case HTTOPRIGHT: mCurrentHit = HTBOTTOMRIGHT; break; case HTBOTTOMLEFT: mCurrentHit = HTTOPLEFT; break; case HTBOTTOMRIGHT: mCurrentHit = HTTOPRIGHT; break; case HTCLIENT: break; } } this->setGeometry(resizeRect); } } QWidget::mouseMoveEvent(e); } int CCuter::OnNcHitTest(MSG *msg) { POINT pt; pt.x = GET_X_LPARAM(msg->lParam); pt.y = GET_Y_LPARAM(msg->lParam); HWND hwnd = (HWND)this->winId(); //::ScreenToClient(hwnd, &pt); RECT rcClient; ::GetWindowRect(hwnd, &rcClient); if (!::IsZoomed(hwnd)) { if((pt.x < (rcClient.right + mTouchBorderWidth)) && (pt.x > (rcClient.right - mTouchBorderWidth)) ) { if((pt.y < (rcClient.top + mTouchBorderWidth)) && (pt.y > (rcClient.top - mTouchBorderWidth)) ) { return HTTOPRIGHT; } if((pt.y < (rcClient.bottom + mTouchBorderWidth)) && (pt.y > (rcClient.bottom - mTouchBorderWidth)) ) { return HTBOTTOMRIGHT; } return HTRIGHT; } if((pt.x < (rcClient.left + mTouchBorderWidth)) && (pt.x > (rcClient.left - mTouchBorderWidth)) ) { if((pt.y < (rcClient.top + mTouchBorderWidth)) && (pt.y > (rcClient.top - mTouchBorderWidth)) ) { return HTTOPLEFT; } if((pt.y < (rcClient.bottom + mTouchBorderWidth)) && (pt.y > (rcClient.bottom - mTouchBorderWidth)) ) { return HTBOTTOMLEFT; } return HTLEFT; } if((pt.y < (rcClient.top + mTouchBorderWidth)) && (pt.y > (rcClient.top - mTouchBorderWidth)) ) { if((pt.x < (rcClient.right + mTouchBorderWidth)) && (pt.x > (rcClient.right - mTouchBorderWidth)) ) { return HTTOPRIGHT; } if((pt.x < (rcClient.left + mTouchBorderWidth)) && (pt.x > (rcClient.left - mTouchBorderWidth)) ) { return HTTOPLEFT; } return HTTOP; } if((pt.y < (rcClient.bottom + mTouchBorderWidth)) && (pt.y > (rcClient.bottom - mTouchBorderWidth)) ) { if((pt.x < (rcClient.right + mTouchBorderWidth)) && (pt.x > (rcClient.right - mTouchBorderWidth)) ) { return HTBOTTOMRIGHT; } if((pt.x < (rcClient.left + mTouchBorderWidth)) && (pt.x > (rcClient.left - mTouchBorderWidth)) ) { return HTBOTTOMLEFT; } return HTBOTTOM; } } // if (pt.y < mTitleBarRect.height()) // { // return HTCAPTION; // } return HTCLIENT; } int CCuter::OnNcHitTest(QPoint pos) { QRect rcClient = this->rect(); if((pos.x() < (rcClient.right() + mTouchBorderWidth)) && (pos.x() > (rcClient.right() - mTouchBorderWidth)) ) { if((pos.y() < (rcClient.top() + mTouchBorderWidth)) && (pos.y() > (rcClient.top() - mTouchBorderWidth)) ) { return HTTOPRIGHT; } if((pos.y() < (rcClient.bottom() + mTouchBorderWidth)) && (pos.y() > (rcClient.bottom() - mTouchBorderWidth)) ) { return HTBOTTOMRIGHT; } return HTRIGHT; } if((pos.x() < (rcClient.left() + mTouchBorderWidth)) && (pos.x() > (rcClient.left() - mTouchBorderWidth)) ) { if((pos.y() < (rcClient.top() + mTouchBorderWidth)) && (pos.y() > (rcClient.top() - mTouchBorderWidth)) ) { return HTTOPLEFT; } if((pos.y() < (rcClient.bottom() + mTouchBorderWidth)) && (pos.y() > (rcClient.bottom() - mTouchBorderWidth)) ) { return HTBOTTOMLEFT; } return HTLEFT; } if((pos.y() < (rcClient.top() + mTouchBorderWidth)) && (pos.y() > (rcClient.top() - mTouchBorderWidth)) ) { if((pos.x() < (rcClient.right() + mTouchBorderWidth)) && (pos.x() > (rcClient.right() - mTouchBorderWidth)) ) { return HTTOPRIGHT; } if((pos.x() < (rcClient.left() + mTouchBorderWidth)) && (pos.x() > (rcClient.left() - mTouchBorderWidth)) ) { return HTTOPLEFT; } return HTTOP; } if((pos.y() < (rcClient.bottom() + mTouchBorderWidth)) && (pos.y() > (rcClient.bottom() - mTouchBorderWidth)) ) { if((pos.x() < (rcClient.right() + mTouchBorderWidth)) && (pos.x() > (rcClient.right() - mTouchBorderWidth)) ) { return HTBOTTOMRIGHT; } if((pos.x() < (rcClient.left() + mTouchBorderWidth)) && (pos.x() > (rcClient.left() - mTouchBorderWidth)) ) { return HTBOTTOMLEFT; } return HTBOTTOM; } // if (pt.y < mTitleBarRect.height()) // { // return HTCAPTION; // } return HTCLIENT; } void CCuter::contextMenuEvent(QContextMenuEvent *e) { QMenu menu; QAction* acCut = menu.addAction(QString::fromLocal8Bit("擷取")); QAction* acCancel = menu.addAction(QString::fromLocal8Bit("取消")); QAction* tag = menu.exec(e->globalPos()); if(tag == acCut) { emit cut(); } else if(tag == acCancel) { emit cancle(); } }
CScreenShoot.h
#ifndef CSCREENSHOOT_H #define CSCREENSHOOT_H #include <QWidget> #include <QPixmap> #include <QEventLoop> class CCuter; class CScreenShoot: public QWidget { Q_OBJECT public: CScreenShoot(); private: static CScreenShoot* gInstance ; //* 截圖單例 QPixmap mPixmapBackground; //* 待截圖幕 QPixmap mCutPixmap ; //* 被截圖幕 CCuter* mCuter ; //* 截圖選擇器 QEventLoop mLoop ; //* 內迴圈 bool mIsInitCuterSize ; //* 當前是否可以改變截圖選擇器的尺寸 void paintEvent(QPaintEvent* e); bool eventFilter(QObject *obj, QEvent *e); void keyPressEvent(QKeyEvent *e); void mousePressEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e); private slots: void cutPixmap(); //* 根據選擇器的位置和尺寸截圖 void cancel(); //* 取消 public: static CScreenShoot* instance(); bool cut (); //* 截圖成功返回true,否則返回false QPixmap pixmap(); //* 當前被擷取的螢幕 }; #endif // CSCREENSHOOT_H
CScreenShoot.cpp
#include "CScreenShoot.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QScreen>
#include <QPainter>
#include <QDebug>
#include <Windows.h>
#include <QPainterPath>
#include <QKeyEvent>
#include <QMouseEvent>
#include "CCuter.h"
CScreenShoot* CScreenShoot::gInstance = NULL;
CScreenShoot::CScreenShoot():
mIsInitCuterSize(false)
, mCuter(NULL)
{
this->setWindowFlags(Qt::FramelessWindowHint| Qt::WindowStaysOnTopHint | Qt::Tool);
this->setMouseTracking(true);
mCuter = new CCuter;
mCuter->setParent(this);
mCuter->installEventFilter(this);
connect(mCuter, &CCuter::cut , this, &CScreenShoot::cutPixmap);
connect(mCuter, &CCuter::cancle, this, &CScreenShoot::cancel );
}
void CScreenShoot::paintEvent(QPaintEvent *e)
{
QWidget::paintEvent(e);
QPainter painter(this);
painter.save();
// bkg
painter.drawPixmap(0,0, mPixmapBackground);
if(mCuter->isVisible())
{
// mask
QPainterPath maskLayer;
QPolygon polygon;
QRect bkgRect = this->rect();
QRect cutRect = mCuter->geometry();
polygon.append(bkgRect.topLeft());
polygon.append(bkgRect.topRight());
polygon.append(bkgRect.bottomRight());
polygon.append(bkgRect.bottomLeft());
polygon.append(bkgRect.topLeft());
polygon.append(cutRect.topLeft());
polygon.append(cutRect.topRight());
polygon.append(cutRect.bottomRight());
polygon.append(cutRect.bottomLeft());
polygon.append(cutRect.topLeft());
maskLayer.addPolygon(polygon);
QBrush br(QColor(0,0,0,125));
painter.fillPath(maskLayer, br);
// selector
painter.setPen(QPen(Qt::blue, 2));
QRect tagRect = mCuter->geometry();
painter.drawRect(tagRect);
QPainterPath path;
QRect rect1(tagRect.topLeft() + QPoint(-3, -3), QSize(8, 8));
QRect rect2(tagRect.topRight() + QPoint(-3, -3), QSize(8, 8));
QRect rect3(tagRect.bottomLeft() + QPoint(-3, -3), QSize(8, 8));
QRect rect4(tagRect.bottomRight() + QPoint(-3, -3), QSize(8, 8));
QRect rect5(tagRect.topLeft() + QPoint(tagRect.width()/2 - 3, -3), QSize(8, 8));
QRect rect6(tagRect.topLeft() + QPoint( -3, tagRect.height()/2 - 3) , QSize(8, 8));
QRect rect7(tagRect.bottomRight() + QPoint(-tagRect.width()/2 - 3, -3) , QSize(8, 8));
QRect rect8(tagRect.bottomRight() + QPoint(-3, -tagRect.height()/2 - 3) , QSize(8, 8));
path.addRect(rect1);
path.addRect(rect2);
path.addRect(rect3);
path.addRect(rect4);
path.addRect(rect5);
path.addRect(rect6);
path.addRect(rect7);
path.addRect(rect8);
painter.fillPath(path, Qt::blue);
// size info
QString sizeInfo = QString::number(mCuter->geometry().width()) + QString::fromLocal8Bit("×") + QString::number(mCuter->geometry().height());
painter.setPen(QPen(Qt::white, 2));
painter.drawText(mCuter->pos() + QPoint(4, - 4), sizeInfo);
}
else
{
// mask
QBrush br(QColor(0,0,0,125));
painter.fillRect(this->rect(), br);
}
painter.restore();
}
bool CScreenShoot::eventFilter(QObject *obj, QEvent *e)
{
bool res = QWidget::eventFilter(obj, e);
if(obj == mCuter)
{
switch (e->type()) {
case QEvent::Move:
case QEvent::Resize:
{
this->update();
}
break;
default:
break;
}
}
return res;
}
void CScreenShoot::keyPressEvent(QKeyEvent *e)
{
if(e->key() == Qt::Key_Escape)
{
emit mCuter->cancle();
}
QWidget::keyPressEvent(e);
}
void CScreenShoot::mousePressEvent(QMouseEvent *e)
{
QWidget::mousePressEvent(e);
if(!mCuter->isVisible())
{
mIsInitCuterSize = true;
QRect resizeRect(e->pos(),e->pos());
mCuter->setGeometry(resizeRect);
mCuter->setVisible(true);
}
}
void CScreenShoot::mouseReleaseEvent(QMouseEvent *e)
{
QWidget::mouseReleaseEvent(e);
mIsInitCuterSize = false;
}
void CScreenShoot::mouseMoveEvent(QMouseEvent *e)
{
if(mIsInitCuterSize)
{
QRect resizeRect = mCuter->geometry();
resizeRect.setBottomRight(e->pos());
if(resizeRect.left() > resizeRect.right())
{
int t = resizeRect.left();
resizeRect.setLeft(resizeRect.right());
resizeRect.setRight(t);
}
if(resizeRect.top() > resizeRect.bottom())
{
int t = resizeRect.top();
resizeRect.setTop(resizeRect.bottom());
resizeRect.setBottom(t);
}
mCuter->setGeometry(resizeRect);
}
QWidget::mouseMoveEvent(e);
}
void CScreenShoot::cutPixmap()
{
mCutPixmap = mPixmapBackground.copy(mCuter->geometry());
mLoop.exit(1);
}
void CScreenShoot::cancel()
{
mCutPixmap = QPixmap();
mLoop.exit(0);
}
CScreenShoot *CScreenShoot::instance()
{
if(gInstance == NULL)
{
gInstance = new CScreenShoot;
}
return gInstance;
}
bool CScreenShoot::cut()
{
qDebug() << "cut...";
QRect desktopRect = qApp->desktop()->geometry();
mPixmapBackground = qApp->primaryScreen()->grabWindow(qApp->desktop()->winId(),
0,
0,
desktopRect.width(),
desktopRect.height());
this->setGeometry(desktopRect);
mCuter->hide();
this->show();
this->activateWindow();
int res = mLoop.exec();
this->close();
if(res > 0)
return true;
else
return false;
}
QPixmap CScreenShoot::pixmap()
{
return mCutPixmap;
}
呼叫方式:
#include <QApplication>
#include <CScreenShoot.h>
#include <CCuter.h>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug() << "done:" << CScreenShoot::instance()->cut();
if(CScreenShoot::instance()->cut())
{
qDebug() << "done.";
CScreenShoot::instance()->pixmap().save("./screen_shoot.bmp");
}
else
{
qDebug() << "cancel.";
}
return 0;
}
歡迎評論區交流。