Qt 模仿QQ截圖 動態吸附直線

最近在學Qt。學東西怎麼能不動手。

就寫了些小程序。看QQ截圖能夠動態吸附直線的功能挺有意思,所以就模仿了一個。

先上效果圖

界面很簡單。。呵呵


移動鼠標,會把鼠標所在最小矩形選中。把沒有選中的地方給模糊化,以示我們選中的區域很清楚。


還可以選中窗口中控件的區域。


小菜單


截圖效果


編程思路:

1.動態找到鼠標所在區域的矩形,肯定是要獲得桌面上每個窗口以及其子控件的大小位置屬性。

想獲得這些屬性Qt貌似沒有提供相關的API,只能用windows的API  EnumWindows 和 EnumChildWindows枚舉出所有的窗口的位置座標和大小屬性保存在 一個vector中。

2.有了位置和大小(保存在一個Rect中就行了)就好辦了。重寫Qt的鼠標移動事件,自己定義了一個結構體

  1. struct MyRect   
  2. {  
  3.     QRect myRect_;  //矩形  
  4.     int distance;   //鼠標當前點到 所有邊的距離之和,用於比較  
  5. };  
每當鼠標移動就把每個包含鼠標當前點的矩形保存到myRect_中並且計算他的大小distance。

然後找到最小的distance對應的矩形。這個就是上圖我們要顯示的矩形了。

3.該怎麼處理??Qt你們都曉得把。

我是通過QPixmap類的grabWindow 獲得整個屏幕,然後 組合繪圖 變色整個屏幕。

當鼠標移動到某個區域時 把這個區域 清晰顯示。即上圖效果。

4.保存圖片QPixmap的save即可。


說了這麼多了上代碼把。

CPP。

  1. #include "imagewidget.h"  
  2. #include <QPainter>  
  3. #include <QColor>  
  4. #include <QMessageBox>  
  5. #include <QByteArray>  
  6. #include <QBuffer>  
  7. #include <QPainter>  
  8. #include <QDesktopWidget>  
  9. #include <QPen>  
  10.   
  11.   
  12. #include <Windows.h>  
  13. #include <vector>  
  14.   
  15.   
  16.   
  17. std::vector<QRect> allWindowRect;     //用於存儲所有的窗口  
  18. std::vector<HWND> allWindowHwnd;      //用於存儲所有的窗口句柄  
  19. std::vector<MyRect> myRectRestlt;     // 找到所有包含 鼠標當前移動點的矩形,並保存其到各邊的距離之和。  
  20.   
  21.   
  22. //聲明回調函數  
  23. bool CALLBACK MyEnumWindowsProc(HWND hwnd,LPARAM lParam);  
  24.   
  25. ImageWidget::ImageWidget(QWidget *parent)  
  26.     : QWidget(parent)  
  27. {  
  28.     ui.setupUi(this);  
  29.   
  30.     //用於獲取窗口大小  
  31.     QDesktopWidget *dtw = QApplication::desktop();   
  32.     //獲得 整個屏幕  
  33.     pixmap_ = pixmap_.grabWindow(QApplication::desktop()->winId(),0,0,dtw->width(),dtw->height());  
  34.   
  35.     isPressed = false;  
  36.     isDragging = false;  
  37.   
  38.     captureMenu_ = new CaptureMenu();  
  39.   
  40.     //打開鼠標 跟蹤  
  41.     setMouseTracking(true);  
  42.   
  43.     //關聯 用於保存文件名  
  44.     connect(captureMenu_,SIGNAL(toSaveFile(QString)),this,SLOT(slotGetFileName(QString)));  
  45.   
  46.     //遍歷窗口 獲得各個窗口的大小  
  47.     ::EnumWindows((WNDENUMPROC)MyEnumWindowsProc,0);  
  48. }  
  49.   
  50. ImageWidget::~ImageWidget()  
  51. {  
  52. }  
  53. void ImageWidget::paintEvent(QPaintEvent *event)  
  54. {  
  55.     QPainter painter(this);  
  56.     pixmap_ = pixmap_.scaled(width(),height(),Qt::KeepAspectRatio);  
  57.   
  58.   
  59.     //pixmap_沒有 alpha通道 添加通道  
  60.     QPixmap temp(pixmap_.size());  
  61.     temp.fill(Qt::transparent);  
  62.   
  63.     QPainter p(&temp);  
  64.     p.setCompositionMode(QPainter::CompositionMode_Source);  
  65.     p.drawPixmap(0, 0, pixmap_);  
  66.     p.setCompositionMode(QPainter::CompositionMode_DestinationIn);  
  67.     p.fillRect(temp.rect(), QColor(50, 50, 50, 100)); //把圖片調 暗 以顯示截圖全屏  
  68. //  pixmap_ = temp;  
  69.   
  70.   
  71.     //水印????  
  72.     painter.drawPixmap(0,0,temp);  
  73.     QPen penWather;  
  74.     penWather.setWidth(10);  
  75.     penWather.setBrush(QColor(125,125,125,125));  
  76.     painter.setPen(penWather);  
  77.     QString tempStr;  
  78.     tempStr = QString(tr("開始按鈕X:%1 Y:%2 移動中的X:%3 Y:%4")).arg(pStart_.x()).arg(pStart_.y()).arg(pMove_.x()).arg(pMove_.y());  
  79.     painter.drawText(100,100,tempStr);  
  80.   
  81.     //顯示 截圖拖動的區域  
  82.     QPen pen;  
  83.     pen.setWidth(5);  
  84.     pen.setColor(QColor(0,255,255,127));  
  85.     painter.setPen(pen);  
  86.   
  87.     if (isDragging)  
  88.     {  
  89.         painter.drawPixmap(pStart_.x(),pStart_.y(),pixmap_,pStart_.x(),pStart_.y(),pMove_.x()-pStart_.x(),pMove_.y()-pStart_.y());  
  90.         painter.drawRect(pStart_.x()-2,pStart_.y()-2,pMove_.x()-pStart_.x()-2,pMove_.y()-pStart_.y()-2);  
  91.     }  
  92.     else   
  93.     {  
  94.         painter.drawPixmap(miniRect.myRect_.left(),miniRect.myRect_.top(),pixmap_,miniRect.myRect_.left(),miniRect.myRect_.top(),miniRect.myRect_.width(),miniRect.myRect_.height());  
  95.         painter.drawRect(miniRect.myRect_.left()-2, miniRect.myRect_.top()-2, miniRect.myRect_.width()-2, miniRect.myRect_.height()-2);  
  96.     }  
  97. }  
  98. void ImageWidget::mousePressEvent(QMouseEvent *event)  
  99. {  
  100.     pStart_.setX(event->x());  
  101.     pStart_.setY(event->y());  
  102.       
  103.     isPressed = true;  
  104. }  
  105.   
  106. void ImageWidget::mouseMoveEvent(QMouseEvent *event)  
  107. {  
  108.     if (isPressed)      //如果按下 鼠標 開始 區域截圖  
  109.     {  
  110.         isDragging = true;  
  111.         pMove_.setX(event->x());  
  112.         pMove_.setY(event->y());  
  113.     }  
  114.     else            //如果沒有按下鼠標 開始自動尋找合適窗口  //、應該改爲 找到距離最近的 矩形塊 。。。!!!!!!  
  115.     {  
  116.         //每次移動都清空  
  117.         myRectRestlt.clear();  
  118.         for (std::vector<QRect>::iterator it = allWindowRect.begin()+1;it != allWindowRect.end();it++)  
  119.         {  
  120.             if (it->contains(event->x(),event->y()))  
  121.             {  
  122.                 calculateRectDistance(*it);  
  123.             }  
  124.         }  
  125.         MyRect tempMinRect;  
  126.         for(std::vector<MyRect>::iterator it = myRectRestlt.begin();it != myRectRestlt.end();it++)  
  127.         {  
  128.             if (it->distance < tempMinRect.distance)  //找到最小的矩形  
  129.             {  
  130.                 tempMinRect = *it;      //  
  131.             }  
  132.         }  
  133.         miniRect = tempMinRect;  
  134.     }  
  135.     update();  
  136. }  
  137. void ImageWidget::mouseReleaseEvent(QMouseEvent *event)  
  138. {  
  139.     //記錄 結束點  
  140.     if (isDragging)  
  141.     {  
  142.         pEnd_.setX(event->x());  
  143.         pEnd_.setY(event->y());  
  144.     }  
  145.     else  
  146.     {  
  147.         pStart_.setX(miniRect.myRect_.left());  
  148.         pStart_.setY(miniRect.myRect_.top());  
  149.         pEnd_.setX(miniRect.myRect_.right());  
  150.         pEnd_.setY(miniRect.myRect_.bottom());  
  151.     }  
  152.   
  153.     isPressed = false;  
  154.     //isDragging = false;  
  155.   
  156.     //新建菜單窗口  
  157.     captureMenu_->move(event->x()-152,event->y());  
  158.     captureMenu_->setWindowFlags(Qt::FramelessWindowHint);  
  159.     captureMenu_->exec();  
  160.   
  161.     //退出窗口  
  162.     close();  
  163.     //發射 信號給截圖軟件窗口 可以顯示  
  164.     emit beVisible();  
  165.   
  166. }  
  167. //回調函數  
  168. bool CALLBACK MyEnumWindowsProc(HWND hwnd,LPARAM lParam)  
  169. {  
  170.     if (::IsWindow(hwnd) && ::IsWindowVisible(hwnd))  
  171.     {  
  172.         RECT tempRect;  
  173.         QRect tempQRect;  
  174.         ::GetWindowRect(hwnd,&tempRect);  
  175.           
  176.         tempQRect.setTopLeft(QPoint(tempRect.left,tempRect.top));  
  177.         tempQRect.setBottomRight(QPoint(tempRect.right,tempRect.bottom));  
  178.       
  179.   
  180.         allWindowRect.push_back(tempQRect);  
  181.         allWindowHwnd.push_back(hwnd);  
  182.   
  183.         ::EnumChildWindows(hwnd,(WNDENUMPROC)MyEnumWindowsProc,0);  
  184.     }  
  185.     return true;  
  186. }  
  187. void ImageWidget::slotGetFileName(QString filename)  
  188. {  
  189.     pixmapSave_ = pixmap_.copy(pStart_.x(),pStart_.y(),pEnd_.x()-pStart_.x(),pEnd_.y()-pStart_.y());  
  190.     //保存截圖  
  191.     QByteArray bytes;//用於存放2進制數據  
  192.     QBuffer buffer(&bytes); //設置緩存  
  193.     buffer.open(QIODevice::ReadOnly);  
  194.     pixmapSave_.save(filename,"PNG",1);  
  195.   
  196. }  
  197. void ImageWidget::calculateRectDistance(QRect rect)  
  198. {  
  199.     int dis = rect.width() + rect.height();  
  200.     MyRect tempMyRect;  
  201.     tempMyRect.myRect_ = rect;  
  202.     tempMyRect.distance = dis;  
  203.     //添加進入  
  204.     myRectRestlt.push_back(tempMyRect);  
  205. }  

。H

  1. #ifndef IMAGEWIDGET_H  
  2. #define IMAGEWIDGET_H  
  3.   
  4. #include <QWidget>  
  5. #include "ui_imagewidget.h"  
  6. #include <QPixmap>  
  7. #include <QPoint>  
  8. #include <QMouseEvent>  
  9. #include <capturemenu.h>  
  10. #include <QRect>  
  11.   
  12. struct MyRect   
  13. {  
  14.     QRect myRect_;  //矩形  
  15.     int distance;   //鼠標當前點到 所有邊的距離之和,用於比較  
  16. };  
  17.   
  18. class ImageWidget : public QWidget  
  19. {  
  20.     Q_OBJECT  
  21.   
  22. public:  
  23.     ImageWidget(QWidget *parent = 0);  
  24.     ~ImageWidget();  
  25.   
  26.     void paintEvent(QPaintEvent *event);  
  27.     //重寫 鼠標按下 事件,記錄截圖起始點  
  28.     void mousePressEvent(QMouseEvent *event);  
  29.     //重寫 鼠標松下 事件,記錄截圖結束點  
  30.     void mouseReleaseEvent(QMouseEvent *event);  
  31.     //重寫 鼠標移動 事件,當拉動截圖區域時 改變截圖區域爲正常圖片(非蒙塵)  
  32.     void mouseMoveEvent(QMouseEvent *event);  
  33.     //用於計算 鼠標當前點到各個邊的距離之和  
  34.     void calculateRectDistance(QRect rect);  
  35. private:  
  36.     Ui::ImageWidget ui;  
  37.     QPixmap pixmap_;    //用於顯示 截的整個屏幕  
  38.     QPixmap pixmapSave_; //用於 保存截圖  
  39.   
  40.     QPoint pStart_; //記錄開始截圖位置  
  41.     QPoint pEnd_;   //記錄結束截圖位置  
  42.     QPoint pMove_;  //記錄移動中的座標  
  43.     bool isPressed; //是否按下按鈕  
  44.     bool isDragging;    //是否用戶拖選  
  45.   
  46.     MyRect miniRect;    //最小矩形  
  47.   
  48.     CaptureMenu *captureMenu_;  //截圖結束時的菜單  
  49.     QString fullPath;   //保存文件名以及 路徑  
  50.   
  51.     public slots:  
  52.         void slotGetFileName(QString filename);  
  53.   
  54. signals:  
  55.         void beVisible();  //給 截圖軟件發射可見 信號  
  56. };  
  57.   
  58. #endif // IMAGEWIDGET_H  

貼了2個最重要的文件。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章