Qt 5中如何捕获双显示器的屏幕截图

5
在Qt应用程序中,我正在使用以下代码片段来截取完整桌面的屏幕截图:
QDesktopWidget* dw = QApplication::desktop();
QPixmap pixmap = QPixmap::grabWindow(dw->winId(), 0, 0,
                                     dw->width(), dw->height());
pixmap.save(name, "JPG", screenshot_quality);

这种方法在Linux和Windows上都非常有效,而且对于双显示器无论屏幕分辨率如何,它都能正常工作,即使两个显示器使用不同的分辨率仍然可以正常工作。 但是,在Qt 5中,我会得到以下运行时警告:

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

我查阅了Qt 5文档,并写下了以下内容:

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

但是这种方法无法捕捉第二屏幕。
因此我进行了更多搜索,根据这个帖子,使用Qt5全屏截图,我设计了以下的截图捕捉方式:
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);

很不幸,这个方法也不起作用。

引起我的注意的是,在Qt 4中使用的方法运行良好。因此,我想象一定有办法在Qt 5中实现它。

所以,我的问题是如何在Qt 5中完成它?

编辑:这是我解决的方式:

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;
}

感谢 @ddriver!

你使用的Qt 5版本是哪个?是5.0、5.1、5.2等等? - vladon
@vladon:5.5.1。我使用的是minGW 32位。 - lrleon
最新的5.6版本修复了多显示器的一些问题,你能否检查一下? - vladon
2个回答

5

当然,QGuiApplication::primaryScreen() 将给你一个单独的屏幕。

您可以使用 QList<QScreen *> QGuiApplication::screens() 获取与应用程序关联的所有屏幕,为所有屏幕拍摄截图,然后创建另一个空白图像,根据您想要组合屏幕的方式调整其大小,并使用 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;
}

感谢您的回答@ddriver。我会考虑您的想法。然而,引起我的注意的是,在Qt 4中更容易实现。也许在Qt 5中有等效的方法。 - lrleon
也许有,也许没有,也许废弃功能存在很好的理由。无论如何,实现我的建议最多只需要5分钟。 - dtech
也许你是对的@ddriver。但我不了解QPainter类。所以我估计这会花费我超过5分钟的时间。我会去研究一下,但任何提示都是受欢迎的。 - lrleon
1
@lrleon 看一下答案编辑,我这里只有一个显示器,还没有测试过,但应该可以工作。 - dtech
没关系,在Virtualbox中你在或不在都无所谓。Windows并不知道这一点。 - vladon
显示剩余4条评论

3
此外,您可以使用主屏幕(桌面)的虚拟几何,无需额外循环和计算即可捕获整个桌面:
QRect desktopGeometry = qApp->primaryScreen()->virtualGeometry();
QPixmap desktopPixmap = qApp->primaryScreen()->grabWindow(qApp->desktop()->winId(), desktopGeometry.x(), desktopGeometry.y(), desktopGeometry.width(), desktopGeometry.height());

请参见:QDesktopWidget 更新: 目前,由于某些原因,Qt将QApplication::desktop()QDesktopWidget标记为过时。因此,对于新项目,建议使用枚举屏幕的方法。无论如何,对于旧版本和当前版本的Qt,此解决方案应该按预期工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接