2013-06-17 2 views
6

Мне нужно захватить каждый кадр чертежа QML (QtQuick 2) и отправить его по сети. На данный момент я использовал метод перечисленные ниже, однако этот метод имеет два больших недостаткаЗахват буфера рисования QML, без отображения

1) Благодаря функции Qt5 документации grabWindow() имеет производительность вопросы

2) Он не может работать со скрытым окном QML

Возможно ли получить буфер рендеринга OpenGL сразу после QQuickWindow :: afterRendering? Использование FBOs? Общий контекст opengl?

class Grab: public QObject 
{ 
public: 
Grab(QQuickWindow * wnd) : wnd_(wnd) {} 

public slots: 

    void Grabme() 
    { 
     QImage image = wnd_->grabWindow(); 
    } 

private: 

QQuickWindow *wnd_; 
}; 

int main(int argc, char *argv[]) 
{ 
QGuiApplication app(argc, argv); 


QtQuick2ApplicationViewer viewer; 
viewer.setMainQmlFile(QStringLiteral("qml/grab1/main.qml")); 
viewer.showExpanded(); 

Grab grab(&viewer); 
QObject::connect(&viewer, &QtQuick2ApplicationViewer::frameSwapped, 
        &grab, &Grab::Grabme, Qt::DirectConnection); 


return app.exec(); 
} 

ответ

8

Пример ниже может захватить любой qml-контент в FBO, а затем отправить его как изображение через сигнал. Только одна проблема такого подхода - видимость, окно захвата должно быть видимым для успешного захвата. Если кто-то знает, как предотвратить это, вы можете помочь мне и обеспечить более продвинутый подход.

// main.cpp 
int main(int argc, char* argv[]) 
{ 
    QApplication app(argc, argv); 

    GrabWindow grab; 
    grab.setResizeMode(QQuickView::SizeViewToRootObject); 
    grab.setSource(QUrl::fromLocalFile("qml/main.qml")); 
    grab.setFlags(Qt::Popup); 

    grab.show(); 
    return app.exec(); 
} 


// grabwindow.hpp 
#pragma once 
#include <QOpenGLFramebufferObject> 
#include <QScopedPointer> 
#include <QQuickView> 
#include <QImage> 

class GrabWindow: public QQuickView 
{ 
    Q_OBJECT 

signals: 
    void changeImage(const QImage &image); 

public: 
    GrabWindow(QWindow * parent = 0); 

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

private: 
    QScopedPointer<QOpenGLFramebufferObject> fbo_; 
}; 

// grabwindow.cpp 
#include "grabwindow.hpp" 
#include <limits> 

GrabWindow::GrabWindow(QWindow * parent) : 
    QQuickView(parent) 
{ 
    setClearBeforeRendering(false); 
    setPosition(std::numeric_limits<unsigned short>::max(), std::numeric_limits<unsigned short>::max()); 

    connect(this, SIGNAL(afterRendering() ), SLOT(afterRendering() ), Qt::DirectConnection); 
    connect(this, SIGNAL(beforeRendering()), SLOT(beforeRendering()), Qt::DirectConnection); 
} 

void GrabWindow::afterRendering() 
{ 
    if(!fbo_.isNull()) 
    { 
    emit changeImage(fbo_->toImage()); 
    } 
} 

void GrabWindow::beforeRendering() 
{ 
    if (!fbo_) 
    { 
     fbo_.reset(new QOpenGLFramebufferObject(size(), QOpenGLFramebufferObject::NoAttachment)); 
     setRenderTarget(fbo_.data()); 
    } 
} 
+0

этот код дает мне ошибку: ошибка C2027: использование неопределенного типа 'QOpenGLFramebufferObject' 1> C: \ Qt \ Qt5.1.0 \ 5.1.0 \ msvc2010 \ включать \ QtQuick/qquickwindow.h (57): см. объявление «QOpenGLFramebufferObject» 1> grab_window.cpp (16): ошибка C2232: '-> QScopedPointer :: isNull': левый операнд имеет тип 'class', используйте '. – otto

+0

Вы должны проверить, скомпилирована ли ваша версия Qt с поддержкой OpenGL, если вы загрузите ее с официального сайта, что она должна быть. Кроме того, в отношении msvc2010 вам необходимо создать правильный файл проекта с включенной библиотекой. Я использую файлы проекта cmake и .pro, и все работает на Qt 5.0.2 – Dmitry

+0

да, это причина, я разрабатываю Windows 7 с помощью Visual Studio 2010, я использовал макрос QT_NO_OPENGL, иначе он не может найти заголовки GLES2 , – otto

2

Мне удалось найти трюк, чтобы заставить grabWindow() работать, когда окно «не видно». Хитрость заключается в том, чтобы установить visibility: Window.Minimized и flags: Qt.Tool. Окно не отображается пользователю, но для внутренних элементов Qt оно кажется видимым, и вызов метода grabWindow() работает так, как ожидалось. Не забудьте вызвать этот метод только после того, как сцена была инициализирована.

Единственная проблема с этим решением (с которым я столкнулся) заключается в том, что если для свойства color окна установлено значение transparent, захваченное содержимое имеет черный фон.