Два потока с Qt, Awesomium и C++

Рейтинг: 1Ответов: 1Опубликовано: 11.11.2014

Всем привет!

Столкнулся я с проблемой совмещения Qt и Awesomium, а если точнее, то с особенностью Qt. После инициализации главного окна Qt в функции main я выполняю инициализацию ядра Awesomium и загружаю страницу. И вот тут-то и подкралась проблема: GUI виснет во время загрузки страницы. То есть главный цикл Qt выполняется после цикла браузера. А мне нужно создать два потока для главного цикла Awesomium и Qt.
Читав документацию по Qt, я еще больше запутался. Пытаясь что-то сделать, испортил весь проект и повключал кучу библиотек. Прошу помочь сделать второй параллельный поток для главного цикла Awesomium и желательно использовать QThread, а не QTimer и слоты (с ними проблем больше потом будет).

Вот текущий код: algobinary.h

#ifndef ALGOBINARY_H
#define ALGOBINARY_H

#define WIDTH   1600
#define HEIGHT  1200
#define URL     "https://www.goole.com/"

#include <QtGui/QMainWindow>
#include <QtGui/QApplication>
#include <Awesomium/WebCore.h>
#include <Awesomium/BitmapSurface.h>
#include <Awesomium/STLHelpers.h>
#include <QtCore/QTimer>
#include <QtCore/QThread>
#include "ui_algobinary.h"

using namespace Awesomium;

class AlgoBinary : public QMainWindow
{
    Q_OBJECT

public:
    AlgoBinary(QWidget *parent = 0, Qt::WFlags flags = 0);
    ~AlgoBinary();
private:
    Ui::AlgoBinaryClass ui;
};

#endif // ALGOBINARY_H

algobinary.cpp

#include "algobinary.h"

AlgoBinary::AlgoBinary(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags)
{
    ui.setupUi(this);
}

AlgoBinary::~AlgoBinary()
{

}

main.cpp

#include "algobinary.h"

int main(int argc, char *argv[])
{   
    QApplication a(argc, argv);
    AlgoBinary w = new AlgoBinary();
    w.show();

    WebCore* web_core = WebCore::Initialize(WebConfig());
    WebView* view = web_core->CreateWebView(WIDTH, HEIGHT);
    //connect(m_timer,SIGNAL(timeout()),this,SLOT(poll()));
    WebURL url(WSLit(URL));
    view->LoadURL(url);

    while(view->IsLoading())
    {
        web_core->Update();
    }

    BitmapSurface* surface = (BitmapSurface*)view->surface();

    if (surface != 0) 
    {
        surface->SaveToJPEG(WSLit("./result.jpg"));
    }

    return a.exec();
}

Всем заранее спасибо!

Ответы

▲ 1

Если достаточно того, чтобы в отдельном потоке для Awesomium всё выполнялось как показано в вопросе, то просто унаследуйте QThread и переопределите метод run(). Обратите внимание, что в этом случае создание всех объектов классов необходимо будет также делать непосредственно в этом методе. В том числе и их удаление, поскольку при выходе контекста выполнения из метода run() поток прекратит своё существование. Не объект класса QThread, а лишь поток, которым этот класс всего лишь управляет, существуя при этом в главном потоке.

Имеется возможность обойти это ограничение и перенести объект класса QThread непосредственно в поток, воспользовавшись методом QObject::moveToThread(). В этом случае станет возможно в аргументы класса поставить создаваемые объекты Awesomium вне метода run() и соответственно безопасно обращаться к ним во время работы потока.

Другой вариант: использовать сигналы и слоты для управления исполнением QThread. Потребуется отдельный класс э-э-э... работник, Worker. В этот класс переносим всё, что связано с Awesomium и создаём в нём слот, например, с наименованием void process() и сигнал void finished(), который должен вызываться на тот момент, когда работа в Worker будет считаться завершённой. В него кладём весь код, который будет работать с этой библитекой: циклы, загрузки веб-страниц, сохранение картинок и т.п. То есть всю логику. Ну а в main.cpp останется только корректно вызвать это хозяйство:

Worker *worker = new Worker;
QThread *thread = new QThread;

//! какие-нибудь параметры можно передать перед выполнением
worker->setMegaParameters(tra-ta-ta);
worker->moveToThread(thread);

connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(thread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

thread->start();

Вот собственно в общих чертах и вся магия. Конечно это не исчерпывающе, но лишь для того, чтобы получить начальное представление.