QQuickWidget 抓图

Posted

技术标签:

【中文标题】QQuickWidget 抓图【英文标题】:QQuickWidget grab image 【发布时间】:2015-07-14 09:27:09 【问题描述】:

我正在保存一张QQuickWidget 的图片,其中包含几个 QML 孩子,但我只有一张空白图片。

C++ 方面:

QQuickWidget* content..
content->setSource(QUrl("qml:/main.qml"));
QPixmap *pm = content->grab(QRect(QPoint(0,0),QSize(-1,-1));
pm->save("someFilename.png", 0, 100);

QML 方面:

Rectangle  width: 5; height: 5; color: "yellow"; objectname: "rootobj"

在 QML 中,我希望动态添加子元素并能够在图像中显示它们。我尝试了QQuickWindow grabWindow 方法与插槽的连接,它可以工作,但它只捕获窗口可见区域,我需要捕获整个 QML。

我相信这不是火箭科学,只是我没有在某个地方得到它。感谢您的回复!

附录:

好的,我不认为这是渲染前后的问题,因为在调用图片抓取器之前我可以看到所有 qml 子项。很抱歉不准确。

c++端:

QQuickWidget* content..
content->setSource(QUrl("qml:/main.qml"));
//do all my dynamic qml children adding

在我可以直观地看到我所有的 qml 之后:

QPixmap *pm = content->grab(QRect(QPoint(0,0),QSize(-1,-1));
pm->save(....

除非我错了,否则我不认为它的渲染问题。谢谢!

【问题讨论】:

已编辑:见帖子中的附录。 【参考方案1】:

问题就像Mido所说的那样。你可以像下面这样解决它。

创建一个类Viewer

查看器.h

class Viewer : public QQuickView
    Q_OBJECT
public:
    explicit Viewer(QWindow *parent = 0);
    Viewer(bool showBar);
    virtual ~Viewer();
    void setMainQmlFile(const QString file);
    void addImportPath(const QString path);

public slots:
    void beforeRendering();
    void afterRendering()

查看器.cpp

#include "viewer.h"

Viewer::Viewer(QWindow *parent)
    : QQuickView(parent)

    setWidth(800);
    setHeight(480);
    connect(this, SIGNAL(beforeRendering()), this, SLOT(beforeRendering()));
    connect(this, SIGNAL(afterRendering()), this, SLOT(afterRendering()));


void Viewer::setMainQmlFile(const QString file)

    setSource(QUrl::fromLocalFile(file));


void Viewer::addImportPath(const QString path)

    engine()->addImportPath(path);

void Viewer::beforeRendering()

//


void Viewer::afterRendering()

//grab window
  QImage img = this->grabWindow();
    img.save(path);
//or your code

main.cpp

Viewer *viewer = new Viewer;
//
///
//
viewer->setMainQmlFile(QStringLiteral("qml/main.qml"));
viewer->show();

【讨论】:

此方法仅适用于显示窗口区域内的东西。如果 QML 对象落在它之外,输出图像将不会显示它。【参考方案2】:

我认为您的问题是捕获屏幕是在呈现 QML 对象之前完成的。 为了使其工作,您应该连接信号的抓取after 渲染信号:

 connect(this, SIGNAL(beforeRendering()), this, SLOT(sltBeforeRendering()));
 connect(this, SIGNAL(afterRendering()), this, SLOT(sltAfterRendering()));

sltAfterRendering 插槽中进行抓取。

为了抓取屏幕,我使用了grabWindow() 函数,并从 QML 中调用它。 这取决于您希望软件的行为。

试试这个:

抓取器.h

#ifndef GRABBER_H
#define GRABBER_H

#include <QObject>
#include <QImage>
#include <QQuickView>

class Grabber : public QObject

    Q_OBJECT
public:
     explicit Grabber(QObject *parent = 0);
     Grabber(QQuickView *view);
     ~Grabber();
     Q_INVOKABLE void capture(QString const &path) const;
signals:

public slots:
private:
   QQuickView*  view_;

;

#endif // GRABBER_H

grabber.cpp

#include "grabber.h"

Grabber::Grabber(QObject *parent) :
    QObject(parent)


Grabber::Grabber(QQuickView* view) :
    view_(view)


Grabber::~Grabber()

    if(view_ != NULL)
    
        delete view_;
        view_ = NULL;
    

void Grabber::capture(QString const &path) const

    QImage img = view_->grabWindow();
    img.save(path);

main.cpp

#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include <QQmlContext>
#include <QQmlEngine>
#include "grabber.h"

int main(int argc, char *argv[])

    QGuiApplication app(argc, argv);

    QtQuick2ApplicationViewer *viewer = new QtQuick2ApplicationViewer;
    Grabber * grab = new Grabber(viewer);
    viewer->setHeight(480);
    viewer->setWidth(800);

    viewer->rootContext()->setContextProperty("grab", grab);
    viewer->setMainQmlFile(QStringLiteral("qml/main.qml"));

    viewer->showExpanded();


    return app.exec();

从 QML 调用它:

grab.capture(path + "imageName.png")

【讨论】:

此方法仅适用于显示窗口区域内的东西。如果 QML 对象落在它之外,输出图像将不会显示它。

以上是关于QQuickWidget 抓图的主要内容,如果未能解决你的问题,请参考以下文章

win10按键精灵抓抓抓图跟鼠标位置颜色不符合

IOS自动抓图

剪切板实现进程间持续抓图转显

Qt之使用GDI实现屏幕快速抓图与缩放

抓图小爬虫

JellyBean 在抓图时表现不同