qt 实现窗口局部镂空,并截图显示。

主要实现2 个功能点:
1 截图
2 窗口镂空
实现截图主要使用QGuiApplication::primaryScreen() 获取到QScreen ,然后调用QGuiApplication::grabWindow函数进行截图,代码示例:

QScreen* screen = QGuiApplication::primaryScreen();
    if(const QWindow* window = windowHandle())
    {
        screen = window->screen();
    }

    if(!screen)
        return;
    originalPixmap = screen->grabWindow(0,rc.left(),rc.top(),rc.right() - rc.left(),rc.bottom() - rc.top());
此时originalPixmap 就是 截取的图片,类型为QPixmap,可直接展示。
实现窗口局部透明,即窗口局部镂空。首先将窗口 搞成全透明,然后在未截图情况下,
绘制窗口背景为半透明;(为什么要先 将窗口弄成全透明那?
因为 不将窗口搞成全透明的话,后面绘制的半透明,
其实 还存在一个窗口背景。做不到真正意义上的全透明)
在截图的情况下将 截图区域不绘制,即全透明,然后绘制非截图区域为半透明。代码如下:
  if(type == QEvent::Paint)
    {
        qDebug() << "start paint";
        QRect rc = ComputeRect(ptStart,ptEnd);
        QPainter painter(screenshot_dlg_);

        if(bCapStart)
        {
            //设置mask 使当前区域全透明
            QPolygon polygon1;
            QRect screenRc = ScreenRect();
            painter.setBrush(QBrush(QColor(0,0,0,100)));
            painter.setPen(QPen(Qt::NoPen));

            polygon1 << QPoint(screenRc.left(),screenRc.top())
                     << QPoint(screenRc.right(),screenRc.top())
                     << QPoint(rc.right(),rc.top())
                     << QPoint(rc.left(),rc.top());
            painter.drawPolygon(polygon1);

            QPolygon polygon2;
            polygon2 << QPoint(screenRc.left(),screenRc.top())
                     << QPoint(screenRc.left(),screenRc.bottom())
                     << QPoint(rc.left(),rc.bottom())
                     << QPoint(rc.left(),rc.top());
            painter.drawPolygon(polygon2);

            QPolygon polygon3;
            polygon3 << QPoint(screenRc.left(),screenRc.bottom())
                     << QPoint(screenRc.right(),screenRc.bottom())
                     << QPoint(rc.right(),rc.bottom())
                     << QPoint(rc.left(),rc.bottom());
            painter.drawPolygon(polygon3);

            QPolygon polygon4;
            polygon4 << QPoint(screenRc.right(),screenRc.top())
                     << QPoint(screenRc.right(),screenRc.bottom())
                     << QPoint(rc.right(),rc.bottom())
                     << QPoint(rc.right(),rc.top());
            painter.drawPolygon(polygon4);
        }
        else
        {
            painter.setBrush(QBrush(QColor(0,0,0,100)));
            painter.drawRect(ScreenRect());
        }
    }
以上4个区域polygon1、polygon2、polygon3、polygon4 即为非截图区域,
我们把它搞成半透明,未绘制的就是全透明了(因为窗口就是全透的)。
完整代码如下:
window.h
    #ifndef WINDOW_H
#define WINDOW_H

#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <QPixmap>
#include <QDialog>
#include <QRect>
#include <QSizeGrip>

class SceenShot:public QWidget
{
public:
    SceenShot(QWidget* parent = Q_NULLPTR);
    void updateShowScreenshot();
    bool eventFilter(QObject *watched, QEvent *event) override;
protected:
    void resizeEvent(QResizeEvent *event) override;
    QRect ScreenRect();
public slots:
    void StartShotScreen();
    void ShootScreen(QRect& rc);
private:
    QRect ComputeRect(QPoint& pt1,QPoint& pt2);

    QDialog*    screenshot_dlg_;
    QPushButton* shot_screen_;
    QVBoxLayout* vbox_;
    QLabel* show_label_;
    QPixmap originalPixmap;


    //绘制截图窗口用的
    QPixmap*    m_Cache;
    QSizeGrip   m_SizeGrip;
};

#endif // WINDOW_H

window.cpp

#include "window.h"
#include <QGuiApplication>
#include <QWindow>
#include <QScreen>
#include <QMouseEvent>
#include <QPainter>
#include <QPen>
#include <QDebug>
#include <QImage>
#include <QBitmap>

SceenShot::SceenShot(QWidget* parent)
    :QWidget(parent),m_SizeGrip(nullptr)
{
    m_Cache = nullptr;
    vbox_ = new QVBoxLayout(this);
    shot_screen_ = new QPushButton(tr("shootScreen"),this);
    shot_screen_->setShortcut(tr("ctrl+a"));
    show_label_ = new QLabel(this);
    show_label_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    show_label_->setAlignment(Qt::AlignCenter);
    show_label_->setMinimumSize(300,300);
    show_label_->setPixmap(originalPixmap);
    connect(shot_screen_,&QPushButton::clicked,this,&SceenShot::StartShotScreen);
    vbox_->addWidget(shot_screen_);
    vbox_->addWidget(show_label_);

    screenshot_dlg_ = new QDialog(this,Qt::FramelessWindowHint);
    screenshot_dlg_->setAttribute(Qt::WA_TranslucentBackground);
    screenshot_dlg_->hide();

    //给Dialog 安装事件过滤器
    screenshot_dlg_->installEventFilter(this);
    //this->setLayout(vbox_);
}

void SceenShot::ShootScreen(QRect& rc)
{
    shot_screen_->setEnabled(false);
    QScreen* screen = QGuiApplication::primaryScreen();
    if(const QWindow* window = windowHandle())
    {
        screen = window->screen();
    }

    if(!screen)
        return;

    originalPixmap = screen->grabWindow(0,rc.left(),rc.top(),rc.right() - rc.left(),rc.bottom() - rc.top());
    updateShowScreenshot();

    shot_screen_->setEnabled(true);
}

void SceenShot::updateShowScreenshot()
{
    show_label_->setPixmap(originalPixmap.scaled(show_label_->size(),
                                                 Qt::KeepAspectRatio,
                                                 Qt::SmoothTransformation));
}

void SceenShot::resizeEvent(QResizeEvent *event)
{
    QSize scaledSize = originalPixmap.size();
    scaledSize.scale(show_label_->size(), Qt::KeepAspectRatio);
    if (!show_label_->pixmap() || scaledSize != show_label_->pixmap()->size())
        updateShowScreenshot();
}

void SceenShot::StartShotScreen()
{
    //获取屏幕大小信息
    QScreen* primaryScreen = QGuiApplication::primaryScreen();
    QRect rect = primaryScreen->geometry();
    screenshot_dlg_->setGeometry(rect);
    screenshot_dlg_->show();
}

bool SceenShot::eventFilter(QObject *watched, QEvent *event)
{
    static QPoint ptStart ={0,0};
    static QPoint ptEnd ={0,0};
    static bool bCapStart = false;
    QEvent::Type type =  event->type();
    QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
    if(mouse_event && mouse_event->button() == Qt::LeftButton && type == QEvent::MouseButtonPress)
    {
        //鼠标左键按下,记录按下位置
        bCapStart = true;
        ptStart = mouse_event->pos();
    }
    else if(mouse_event && mouse_event->button() == Qt::LeftButton && type == QEvent::MouseButtonRelease)
    {
        //qDebug() << "MouseButtonRelease";
        bCapStart = false;
        QRect rc = ComputeRect(ptStart,ptEnd);
        qDebug() << "x:" << rc.left() << " y:" << rc.top() << " right:" << rc.right() << " bottom:" << rc.bottom();
        ShootScreen(rc);
        ptStart.setX(0);
        ptStart.setY(0);
        ptEnd.setX(0);
        ptEnd.setY(0);
    }
    else if(bCapStart && type == QEvent::MouseMove)
    {
        ptEnd = mouse_event->pos();
        screenshot_dlg_->update();
    }

//    //重写Dialog得绘制事件和改变大小事件
//    if(type == QEvent::Paint)
//    {
//        if(m_Cache != NULL)
//          {
//            QPainter painter(screenshot_dlg_);

//            painter.drawPixmap(0, 0, *m_Cache);

//        #if QT_VERSION >= 0x040500
//            if(!testAttribute(Qt::WA_TranslucentBackground)) screenshot_dlg_->setMask(m_Cache->mask());
//        #else
//            screenshot_dlg_->setMask(m_Cache->mask());
//        #endif
//          }
//    }
//    else if(type == QEvent::Resize)
//    {
//        delete m_Cache;
//        m_Cache = new QPixmap(screenshot_dlg_->size());
//        m_Cache->fill(Qt::transparent);
//        QPainter painter(m_Cache);
//        QColor darkBlue ( 23,  23,  34);
//          QColor lightBlue(177, 177, 203);

//          /********** Window's background **********/
//          QPolygon background;

//          background << QPoint(           0,            16)
//                     << QPoint(          16,             0)
//                     << QPoint(width() -  1,             0)
//                     << QPoint(width() -  1, height() - 33)
//                     << QPoint(width() - 17, height() - 17)
//                     << QPoint(         272, height() - 17)
//                     << QPoint(         256, height() -  1)
//                     << QPoint(          16, height() -  1)
//                     << QPoint(          16,           272)
//                     << QPoint(           0,           256);

//          painter.setPen  (QPen  (darkBlue));
//          painter.setBrush(QBrush(darkBlue));

//          painter.drawPolygon(background);
//          /*****************************************/

//          /********** Window's frame **********/
//          QPolygon frame;

//          frame << QPoint(           4,            20)
//                << QPoint(          20,             4)
//                << QPoint(width() -  4,             4)
//                << QPoint(width() -  4, height() - 37)
//                << QPoint(width() - 20, height() - 21)
//                << QPoint(         268, height() - 21)
//                << QPoint(         252, height() -  5)
//                << QPoint(          20, height() -  5)
//                << QPoint(          20,           268)
//                << QPoint(           4,           252);

//          painter.setPen  (QPen(lightBlue));
//          painter.setBrush(Qt::NoBrush    );

//          painter.drawPolygon(frame);
//          /*****************************************/

//          //m_SizeGrip.move  (width() - 32, height() - 49);
//          //m_SizeGrip.resize(          32,            32);
//    }
    if(type == QEvent::Paint)
    {
        qDebug() << "start paint";
        QRect rc = ComputeRect(ptStart,ptEnd);
        QPainter painter(screenshot_dlg_);

        if(bCapStart)
        {
            //设置mask 使当前区域全透明
            QPolygon polygon1;
            QRect screenRc = ScreenRect();
            painter.setBrush(QBrush(QColor(0,0,0,100)));
            painter.setPen(QPen(Qt::NoPen));

            polygon1 << QPoint(screenRc.left(),screenRc.top())
                     << QPoint(screenRc.right(),screenRc.top())
                     << QPoint(rc.right(),rc.top())
                     << QPoint(rc.left(),rc.top());
            painter.drawPolygon(polygon1);

            QPolygon polygon2;
            polygon2 << QPoint(screenRc.left(),screenRc.top())
                     << QPoint(screenRc.left(),screenRc.bottom())
                     << QPoint(rc.left(),rc.bottom())
                     << QPoint(rc.left(),rc.top());
            painter.drawPolygon(polygon2);

            QPolygon polygon3;
            polygon3 << QPoint(screenRc.left(),screenRc.bottom())
                     << QPoint(screenRc.right(),screenRc.bottom())
                     << QPoint(rc.right(),rc.bottom())
                     << QPoint(rc.left(),rc.bottom());
            painter.drawPolygon(polygon3);

            QPolygon polygon4;
            polygon4 << QPoint(screenRc.right(),screenRc.top())
                     << QPoint(screenRc.right(),screenRc.bottom())
                     << QPoint(rc.right(),rc.bottom())
                     << QPoint(rc.right(),rc.top());
            painter.drawPolygon(polygon4);
        }
        else
        {
            painter.setBrush(QBrush(QColor(0,0,0,100)));
            painter.drawRect(ScreenRect());
        }
    }
    return false;
}

QRect SceenShot::ComputeRect(QPoint& pt1,QPoint& pt2)
{
    QRect rc;
    if(pt1.x() > pt2.x())
    {
        if(pt1.y() > pt2.y())
        {
            //pt1 为右下点
            rc.setTopLeft(pt2);
            rc.setBottomRight(pt1);
        }
        else
        {
            rc.setBottomLeft(pt2);
            rc.setTopRight(pt1);
        }
    }
    else
    {
        if(pt1.y() > pt2.y())
        {
            //pt1 为左下点
            rc.setBottomLeft(pt1);
            rc.setTopRight(pt2);
        }
        else
        {
            rc.setTopLeft(pt1);
            rc.setBottomRight(pt2);
        }
    }

    return rc;
}

QRect SceenShot::ScreenRect()
{
    QScreen* screen = QGuiApplication::primaryScreen();
    return screen->geometry();
}

main.cpp

#include <QApplication>
#include "window.h"

int main(int argc,char* argv[])
{
    QApplication app(argc,argv);
    SceenShot sc;
    sc.show();

    sc.resize(300,300);
    return app.exec();
}

以上就是简单的截图功能。使用鼠标拖拽截图。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值