Qt dynamic adsorption line

Implementation ideas:

1. To dynamically find the rectangle where the mouse is located, you must obtain the size and position attributes of each window and its child controls on the desktop.

In order to obtain these attributes Qt, it seems that there is no relevant API provided. You can only use the windows API EnumWindows and EnumChildWindows to list all the window location coordinates and size attributes and save them in a vector.

2. With location and size (just save in a Rect), it's easy to do. Rewrite the mouse movement event of Qt, and define a structure

struct MyRect   
{  
    QRect myRect_;  //rectangle  
    int distance;   //The sum of the distances from the current mouse point to all edges for comparison  
};  

Every time the mouse moves, each rectangle containing the current mouse point is saved to myRect? And its size distance is calculated. Then find the rectangle for the smallest distance. This is the rectangle we are going to show in the picture above.

3. Handling

The whole screen is obtained through grabWindow of QPixmap class, and then the whole screen is changed by combining drawings. When the mouse moves to an area, the area is clearly displayed.

4. save the QPixmap

 

Code

#include "imagewidget.h"  
#include <QPainter>  
#include <QColor>  
#include <QMessageBox>  
#include <QByteArray>  
#include <QBuffer>  
#include <QPainter>  
#include <QDesktopWidget>  
#include <QPen>  
  
  
#include <Windows.h>  
#include <vector>  
  
  
  
std::vector<QRect> allWindowRect;     //Used to store all windows  
std::vector<HWND> allWindowHwnd;      //Used to store all window handles  
std::vector<MyRect> myRectRestlt;     // Find all the rectangles that contain the mouse's current moving point, and save the sum of their distances to each side.  
  
  
//Declare callback function  
bool CALLBACK MyEnumWindowsProc(HWND hwnd,LPARAM lParam);  
  
ImageWidget::ImageWidget(QWidget *parent)  
    : QWidget(parent)  
{  
    ui.setupUi(this);  
  
    //Used to get window size  
    QDesktopWidget *dtw = QApplication::desktop();   
    //Get the whole screen  
    pixmap_ = pixmap_.grabWindow(QApplication::desktop()->winId(),0,0,dtw->width(),dtw->height());  
  
    isPressed = false;  
    isDragging = false;  
  
    captureMenu_ = new CaptureMenu();  
  
    //Turn on mouse tracking  
    setMouseTracking(true);  
  
    //Association to save file name  
    connect(captureMenu_,SIGNAL(toSaveFile(QString)),this,SLOT(slotGetFileName(QString)));  
  
    //Traverse the window to get the size of each window  
    ::EnumWindows((WNDENUMPROC)MyEnumWindowsProc,0);  
}  
  
ImageWidget::~ImageWidget()  
{  
}  
void ImageWidget::paintEvent(QPaintEvent *event)  
{  
    QPainter painter(this);  
    pixmap_ = pixmap_.scaled(width(),height(),Qt::KeepAspectRatio);  
  
  
    //pixmap? No alpha channel to add channel  
    QPixmap temp(pixmap_.size());  
    temp.fill(Qt::transparent);  
  
    QPainter p(&temp);  
    p.setCompositionMode(QPainter::CompositionMode_Source);  
    p.drawPixmap(0, 0, pixmap_);  
    p.setCompositionMode(QPainter::CompositionMode_DestinationIn);  
    p.fillRect(temp.rect(), QColor(50, 50, 50, 100)); //Darken the picture to show the full screen of the screenshot  
//  pixmap_ = temp;  
  
  
    //Watermark????  
    painter.drawPixmap(0,0,temp);  
    QPen penWather;  
    penWather.setWidth(10);  
    penWather.setBrush(QColor(125,125,125,125));  
    painter.setPen(penWather);  
    QString tempStr;  
    tempStr = QString(tr("Start button X:%1 Y:%2 Mobile X:%3 Y:%4")).arg(pStart_.x()).arg(pStart_.y()).arg(pMove_.x()).arg(pMove_.y());  
    painter.drawText(100,100,tempStr);  
  
    //Show area of screenshot drag  
    QPen pen;  
    pen.setWidth(5);  
    pen.setColor(QColor(0,255,255,127));  
    painter.setPen(pen);  
  
    if (isDragging)  
    {  
        painter.drawPixmap(pStart_.x(),pStart_.y(),pixmap_,pStart_.x(),pStart_.y(),pMove_.x()-pStart_.x(),pMove_.y()-pStart_.y());  
        painter.drawRect(pStart_.x()-2,pStart_.y()-2,pMove_.x()-pStart_.x()-2,pMove_.y()-pStart_.y()-2);  
    }  
    else   
    {  
        painter.drawPixmap(miniRect.myRect_.left(),miniRect.myRect_.top(),pixmap_,miniRect.myRect_.left(),miniRect.myRect_.top(),miniRect.myRect_.width(),miniRect.myRect_.height());  
        painter.drawRect(miniRect.myRect_.left()-2, miniRect.myRect_.top()-2, miniRect.myRect_.width()-2, miniRect.myRect_.height()-2);  
    }  
}  
void ImageWidget::mousePressEvent(QMouseEvent *event)  
{  
    pStart_.setX(event->x());  
    pStart_.setY(event->y());  
      
    isPressed = true;  
}  
  
void ImageWidget::mouseMoveEvent(QMouseEvent *event)  
{  
    if (isPressed)      //If you press the mouse to start the area screenshot  
    {  
        isDragging = true;  
        pMove_.setX(event->x());  
        pMove_.setY(event->y());  
    }  
    else            //If you don't press the mouse to automatically find the right window / /, you should find the nearest rectangular block instead...!!!!!!  
    {  
        //Empty every move  
        myRectRestlt.clear();  
        for (std::vector<QRect>::iterator it = allWindowRect.begin()+1;it != allWindowRect.end();it++)  
        {  
            if (it->contains(event->x(),event->y()))  
            {  
                calculateRectDistance(*it);  
            }  
        }  
        MyRect tempMinRect;  
        for(std::vector<MyRect>::iterator it = myRectRestlt.begin();it != myRectRestlt.end();it++)  
        {  
            if (it->distance < tempMinRect.distance)  //Find the smallest rectangle  
            {  
                tempMinRect = *it;      //  
            }  
        }  
        miniRect = tempMinRect;  
    }  
    update();  
}  
void ImageWidget::mouseReleaseEvent(QMouseEvent *event)  
{  
    //Record end point  
    if (isDragging)  
    {  
        pEnd_.setX(event->x());  
        pEnd_.setY(event->y());  
    }  
    else  
    {  
        pStart_.setX(miniRect.myRect_.left());  
        pStart_.setY(miniRect.myRect_.top());  
        pEnd_.setX(miniRect.myRect_.right());  
        pEnd_.setY(miniRect.myRect_.bottom());  
    }  
  
    isPressed = false;  
    //isDragging = false;  
  
    //New menu window  
    captureMenu_->move(event->x()-152,event->y());  
    captureMenu_->setWindowFlags(Qt::FramelessWindowHint);  
    captureMenu_->exec();  
  
    //Exit window  
    close();  
    //Send signal to screenshot software window for display  
    emit beVisible();  
  
}  
//Callback function  
bool CALLBACK MyEnumWindowsProc(HWND hwnd,LPARAM lParam)  
{  
    if (::IsWindow(hwnd) && ::IsWindowVisible(hwnd))  
    {  
        RECT tempRect;  
        QRect tempQRect;  
        ::GetWindowRect(hwnd,&tempRect);  
          
        tempQRect.setTopLeft(QPoint(tempRect.left,tempRect.top));  
        tempQRect.setBottomRight(QPoint(tempRect.right,tempRect.bottom));  
      
  
        allWindowRect.push_back(tempQRect);  
        allWindowHwnd.push_back(hwnd);  
  
        ::EnumChildWindows(hwnd,(WNDENUMPROC)MyEnumWindowsProc,0);  
    }  
    return true;  
}  
void ImageWidget::slotGetFileName(QString filename)  
{  
    pixmapSave_ = pixmap_.copy(pStart_.x(),pStart_.y(),pEnd_.x()-pStart_.x(),pEnd_.y()-pStart_.y());  
    //Save Screenshot  
    QByteArray bytes;//Used to store binary data  
    QBuffer buffer(&bytes); //Set cache  
    buffer.open(QIODevice::ReadOnly);  
    pixmapSave_.save(filename,"PNG",1);  
  
}  
void ImageWidget::calculateRectDistance(QRect rect)  
{  
    int dis = rect.width() + rect.height();  
    MyRect tempMyRect;  
    tempMyRect.myRect_ = rect;  
    tempMyRect.distance = dis;  
    //Add in  
    myRectRestlt.push_back(tempMyRect);  
}  
#ifndef IMAGEWIDGET_H  
#define IMAGEWIDGET_H  
  
#include <QWidget>  
#include "ui_imagewidget.h"  
#include <QPixmap>  
#include <QPoint>  
#include <QMouseEvent>  
#include <capturemenu.h>  
#include <QRect>  
  
struct MyRect   
{  
    QRect myRect_;  //rectangle  
    int distance;   //The sum of the distances from the current mouse point to all edges for comparison  
};  
  
class ImageWidget : public QWidget  
{  
    Q_OBJECT  
  
public:  
    ImageWidget(QWidget *parent = 0);  
    ~ImageWidget();  
  
    void paintEvent(QPaintEvent *event);  
    //Rewrite the mouse down event and record the starting point of the screenshot  
    void mousePressEvent(QMouseEvent *event);  
    //Rewrite the mouse Panasonic event and record the end point of the screenshot  
    void mouseReleaseEvent(QMouseEvent *event);  
    //Rewrite the mouse movement event. When the screenshot area is pulled, change the screenshot area to a normal image (non dusty)  
    void mouseMoveEvent(QMouseEvent *event);  
    //Used to calculate the sum of the distance from the current mouse point to each edge  
    void calculateRectDistance(QRect rect);  
private:  
    Ui::ImageWidget ui;  
    QPixmap pixmap_;    //The entire screen used to display the section  
    QPixmap pixmapSave_; //Used to save screenshots  
  
    QPoint pStart_; //Record start screenshot location  
    QPoint pEnd_;   //Record end screenshot location  
    QPoint pMove_;  //Record coordinates in motion  
    bool isPressed; //Press button or not  
    bool isDragging;    //User drag or not  
  
    MyRect miniRect;    //Minimum rectangle  
  
    CaptureMenu *captureMenu_;  //Menu at the end of the screenshot  
    QString fullPath;   //Save file name and path  
  
    public slots:  
        void slotGetFileName(QString filename);  
  
signals:  
        void beVisible();  //Send visible signal to screenshot software  
};  
  
#endif // IMAGEWIDGET_H  

 

Tags: Qt Windows Mobile

Posted on Mon, 06 Jan 2020 18:56:21 -0800 by neuro4848