Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Screenshot selection
Forum Updated to NodeBB v4.3 + New Features

Screenshot selection

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 3 Posters 2.4k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    Szary
    wrote on last edited by Szary
    #1

    Hello,
    I'd want to make a desktop application similar to the Windows Snipping Tool, wherein you could take a screenshots. I have a problem with implementation of screenshot selection - I have no idea, how to write this piece of code. I'd like to:

    • dim a bit the picture;
    • user selection has to be in default color;
    • user could resize this selection after taking a screenshot.

    Here is the example, how it should work:
    0_1539893499125_screenshot.jpg

    ODБOïO 1 Reply Last reply
    0
    • S Szary

      Hello,
      I'd want to make a desktop application similar to the Windows Snipping Tool, wherein you could take a screenshots. I have a problem with implementation of screenshot selection - I have no idea, how to write this piece of code. I'd like to:

      • dim a bit the picture;
      • user selection has to be in default color;
      • user could resize this selection after taking a screenshot.

      Here is the example, how it should work:
      0_1539893499125_screenshot.jpg

      ODБOïO Offline
      ODБOïO Offline
      ODБOï
      wrote on last edited by ODБOï
      #2

      @Szary hi,
      https://stackoverflow.com/questions/29087710/how-to-make-a-resizable-rectangle-in-qml

      edit : my bad, this is qml exemple

      1 Reply Last reply
      0
      • Chris KawaC Offline
        Chris KawaC Offline
        Chris Kawa
        Lifetime Qt Champion
        wrote on last edited by Chris Kawa
        #3

        Hi, welcome to the forum.

        It's pretty straightforward.
        To actually capture entire desktop (remember multiple screen setups) you can do something like this:

        QPixmap grabScreenshot()
        {
            QPixmap desktopPixmap = QPixmap(QApplication::desktop()->geometry().size());
            QPainter p(&desktopPixmap);
        
            for (QScreen* screen : QApplication::screens())
                p.drawPixmap(screen->geometry().topLeft(), screen->grabWindow(0));
        
            return desktopPixmap;
        }
        

        Then create a class like this:

        class SelectorWidget : public QDialog
        {
            Q_OBJECT
        public:
            explicit SelectorWidget(QWidget* parent = nullptr);
            QPixmap selectedPixmap;
        protected:
            void mousePressEvent(QMouseEvent* event) override;
            void mouseReleaseEvent(QMouseEvent* event) override;
            void mouseMoveEvent(QMouseEvent* event) override;
            void paintEvent(QPaintEvent* event) override;
        private:
            QPixmap desktopPixmap;
            QRect selectedRect;
        };
        

        Make the window borderless, translucent and covering entire desktop. Grab the screenshot in the constructor:

        SelectorWidget::SelectorWidget(QWidget* parent) : QDialog(parent, Qt::FramelessWindowHint)
        {
            setAttribute(Qt::WA_TranslucentBackground);
            setGeometry(QApplication::desktop()->geometry());
        
            desktopPixmap = grabScreenshot();
        }
        

        On mouse press store the first corner of the selection rectangle:

        void SelectorWidget::mousePressEvent(QMouseEvent* event)
        {
            selectedRect.setTopLeft(event->globalPos());
        }
        

        On mouse move store the second corner and repaint:

        void SelectorWidget::mouseMoveEvent(QMouseEvent* event)
        {
            selectedRect.setBottomRight(event->globalPos());
            update();
        }
        

        On mouse release cut the selected part from the original screenshot and end dialog via accept():

        void SelectorWidget::mouseReleaseEvent(QMouseEvent* event)
        {
            selectedPixmap = desktopPixmap.copy(selectedRect.normalized());
            accept();
        }
        

        On paint draw the original screenshot, then dim the part around selection and draw a red selection rectangle:

        void SelectorWidget::paintEvent(QPaintEvent*)
        {
            QPainter p (this);
            p.drawPixmap(0, 0, desktopPixmap);
        
            QPainterPath path;
            path.addRect(rect());
            path.addRect(selectedRect);
            p.fillPath(path, QColor::fromRgb(255,255,255,200));
        
            p.setPen(Qt::red);
            p.drawRect(selectedRect);
        }
        

        That's it. Now you can use that widget like this to for example copy that selection to clipboard:

        SelectorWidget w;
        if (w.exec() == QDialog::Accepted)
            qApp->clipboard()->setPixmap(w.selectedPixmap);
        
        S 1 Reply Last reply
        8
        • Chris KawaC Chris Kawa

          Hi, welcome to the forum.

          It's pretty straightforward.
          To actually capture entire desktop (remember multiple screen setups) you can do something like this:

          QPixmap grabScreenshot()
          {
              QPixmap desktopPixmap = QPixmap(QApplication::desktop()->geometry().size());
              QPainter p(&desktopPixmap);
          
              for (QScreen* screen : QApplication::screens())
                  p.drawPixmap(screen->geometry().topLeft(), screen->grabWindow(0));
          
              return desktopPixmap;
          }
          

          Then create a class like this:

          class SelectorWidget : public QDialog
          {
              Q_OBJECT
          public:
              explicit SelectorWidget(QWidget* parent = nullptr);
              QPixmap selectedPixmap;
          protected:
              void mousePressEvent(QMouseEvent* event) override;
              void mouseReleaseEvent(QMouseEvent* event) override;
              void mouseMoveEvent(QMouseEvent* event) override;
              void paintEvent(QPaintEvent* event) override;
          private:
              QPixmap desktopPixmap;
              QRect selectedRect;
          };
          

          Make the window borderless, translucent and covering entire desktop. Grab the screenshot in the constructor:

          SelectorWidget::SelectorWidget(QWidget* parent) : QDialog(parent, Qt::FramelessWindowHint)
          {
              setAttribute(Qt::WA_TranslucentBackground);
              setGeometry(QApplication::desktop()->geometry());
          
              desktopPixmap = grabScreenshot();
          }
          

          On mouse press store the first corner of the selection rectangle:

          void SelectorWidget::mousePressEvent(QMouseEvent* event)
          {
              selectedRect.setTopLeft(event->globalPos());
          }
          

          On mouse move store the second corner and repaint:

          void SelectorWidget::mouseMoveEvent(QMouseEvent* event)
          {
              selectedRect.setBottomRight(event->globalPos());
              update();
          }
          

          On mouse release cut the selected part from the original screenshot and end dialog via accept():

          void SelectorWidget::mouseReleaseEvent(QMouseEvent* event)
          {
              selectedPixmap = desktopPixmap.copy(selectedRect.normalized());
              accept();
          }
          

          On paint draw the original screenshot, then dim the part around selection and draw a red selection rectangle:

          void SelectorWidget::paintEvent(QPaintEvent*)
          {
              QPainter p (this);
              p.drawPixmap(0, 0, desktopPixmap);
          
              QPainterPath path;
              path.addRect(rect());
              path.addRect(selectedRect);
              p.fillPath(path, QColor::fromRgb(255,255,255,200));
          
              p.setPen(Qt::red);
              p.drawRect(selectedRect);
          }
          

          That's it. Now you can use that widget like this to for example copy that selection to clipboard:

          SelectorWidget w;
          if (w.exec() == QDialog::Accepted)
              qApp->clipboard()->setPixmap(w.selectedPixmap);
          
          S Offline
          S Offline
          Szary
          wrote on last edited by
          #4

          @Chris-Kawa, thank you so much for very helpful answer. I'll try edit this code and add another features which come to my mind.

          1 Reply Last reply
          0
          • S Offline
            S Offline
            Szary
            wrote on last edited by
            #5

            Which class or classes should I use to make screenshot selection dragable and resizable? I don't think so, that I should use QPainter. I don't want to see a code, I'd like to write it by myself.
            0_1540307537487_4bce7cd0-81d2-4bc9-9645-0dc661a0b19e.jpg

            1 Reply Last reply
            0
            • Chris KawaC Offline
              Chris KawaC Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on last edited by
              #6

              You can modify my example not to accept() on mouse release. From there there are many possible options.

              You could modify mousePressEvent to detect you pressed near the corners or middles of the rectangle, store in some member info about which control point you clicked and then modify the rectangle accordingly in mouseMoveEvent. To draw the points you simply draw small rectangles in paintEvent();

              Another option would be to add a QGraphicsView and QGraphicsScene to the widget. You would then add the control points as QGraphicsRectItem, make them draggable via their item flags and modify the selection rectangle on their move events. This method is a bit heavier but it would save you from implementing the clicking and dragging yourself (it's not very hard anyway, but still).

              1 Reply Last reply
              3
              • S Offline
                S Offline
                Szary
                wrote on last edited by
                #7

                Drawing corner rectangles in paintEvent(), that's what I tried to do, but I haven't been sure, it's correct way. Thank you again for reply, I'll try your tips.

                1 Reply Last reply
                0

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved