Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Screenshot capture of dual monitor in Qt 5

Tags:

c++

qt

In the context of a Qt application, I'm using the following code snippet for taking a screenshot of full desktop:

QDesktopWidget* dw = QApplication::desktop();
QPixmap pixmap = QPixmap::grabWindow(dw->winId(), 0, 0,
                                     dw->width(), dw->height());
pixmap.save(name, "JPG", screenshot_quality);

This approach works pretty well in Linux and Windows and with dual monitor, independently of screen's resolutions; that is, it works still if the two monitors are working with different resolutions. However, with Qt 5 I get the following run-time warning:

static QPixmap QPixmap::grabWindow(WId, int, int, int, int) is deprecated, use QScreen::grabWindow() instead. Defaulting to primary screen.

So I reviewed the Qt 5 doc and I wrote this:

QScreen * screen = QGuiApplication::primaryScreen();
QPixmap pixmap = screen->grabWindow(0);
pixmap.save(name, "JPG", screenshot_quality);

But this approach does not capture the second screen.

So I searched a little more and, according to this thread, Taking Screenshot of Full Desktop with Qt5, I designed the screenshot capture as follows:

QScreen * screen = QGuiApplication::primaryScreen();
QRect g = screen->geometry();
QPixmap pixmap = screen->grabWindow(0, g.x(), g.y(), g.width(), g.height());
pixmap.save(name, "JPG", screenshot_quality);

Unfortunately, this does not work too.

What catches my attention is that the method with Qt 4 works well. Since I imagine there must be some way to make it in Qt 5.

So, my question is how can be done with Qt 5?

EDIT: This is the way as I solved:

QPixmap grabScreens()
{
  QList<QScreen*> screens = QGuiApplication::screens();
  QList<QPixmap> scrs;
  int w = 0, h = 0, p = 0;

  foreach (auto scr, screens)
    {
      QRect g = scr->geometry();
      QPixmap pix = scr->grabWindow(0, g.x(), g.y(), g.width(), g.height());
      w += pix.width();
      h = max(h, pix.height());
      scrs.append(pix);
    }

  QPixmap final(w, h);
  QPainter painter(&final);
  final.fill(Qt::black);
  foreach (auto scr, scrs)
    {
      painter.drawPixmap(QPoint(p, 0), scr);
      p += scr.width();
    }

  return final;
}

Thanks to @ddriver!

like image 222
lrleon Avatar asked Apr 21 '16 15:04

lrleon


People also ask

How do I take a screenshot when I have two monitors?

Screenshots showing both screens:Hit CTRL + PrtScn on your keyboard. Hit CTRL + V to paste the screenshot in Word, Paint, an email, or whatever else you can paste it into.

How do you screenshot on QT?

The newScreenshot() slot prepares a new screenshot. The saveScreenshot() slot saves the last screenshot. The shootScreen() slot takes the screenshot. The updateCheckBox() slot enables or disables the Hide This Window option.


2 Answers

Naturally, QGuiApplication::primaryScreen() will give you a single screen.

You could use QList<QScreen *> QGuiApplication::screens() to get all screens associated with the application, take screenshots for all of them, then create another blank image, size it according to how you want to compose the screens, and manually compose into a final image using QPainter.

QPixmap grabScreens() {
  auto screens = QGuiApplication::screens();
  QList<QPixmap> scrs;
  int w = 0, h = 0, p = 0;
  foreach (auto scr, screens) {
    QPixmap pix = scr->grabWindow(0);
    w += pix.width();
    if (h < pix.height()) h = pix.height();
    scrs << pix;
  }
  QPixmap final(w, h);
  QPainter painter(&final);
  final.fill(Qt::black);
  foreach (auto scr, scrs) {
    painter.drawPixmap(QPoint(p, 0), scr);
    p += scr.width();
  }
  return final;
}
like image 68
dtech Avatar answered Sep 20 '22 02:09

dtech


Also, you can use primary screen(desktop) virtual geometry and capture entire desktop without additional loops and calculations:

QRect desktopGeometry = qApp->primaryScreen()->virtualGeometry();
QPixmap desktopPixmap = qApp->primaryScreen()->grabWindow(qApp->desktop()->winId(), desktopGeometry.x(), desktopGeometry.y(), desktopGeometry.width(), desktopGeometry.height());

See also: QDesktopWidget

Update:

At the moment, QApplication::desktop() and QDesktopWidget are marked as obsolete by the Qt for some reason, so for new projects it's recommended to use approach with screen enumerating. Anyway, for old and current Qt versions this solution have to work as expected.

like image 20
Vadym Senkiv Avatar answered Sep 20 '22 02:09

Vadym Senkiv