Russian Qt Forum
Сентябрь 21, 2024, 14:06 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Фоновая печать из QWebView  (Прочитано 13048 раз)
kirill
Гость
« : Ноябрь 12, 2008, 12:27 »

Пытаюсь распечатать из QWebView достаточно большой html-документ (на 100 страниц) функцией print(QPrinter).

В итоге программа "подмерзает" пока функция не отработает, а работает она довольно долго. Попытался убрать ее в поток.

Код:
class PrintThread : public QThread
{
   Q_OBJECT
public:
   PrintThread(QWebView*, QPrinter*);
protected:
   void run();
   QWebView *wv;
   QPrinter *printer;
};

void PrintThread::run()
{
     wv->print(printer);
}


Пытаюсь печатать так:
Код:
QWebView *webview = new QWebView();
QPrinter *printer = new QPrinter();
//...
PrintThread ptPrint(webview, printer);
ptPrint->start();

Вроде бы печать уходит в фон и в общем-то иногда печатает нормально. Но если попытаться в это время подергать главное окно, то программа валится.
В Output валятся сообщения
Цитировать
QObject::startTimer: timers cannot be started from another thread
QObject::killTimer: timers cannot be stopped from another thread
This may be due to a corruption of the heap, and indicates a bug in vrfstat.exe or any of the DLLs it has loaded.


Вопрос собстна как правильно организовать фоновую печть?
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #1 : Ноябрь 12, 2008, 12:42 »

Собственно странного ничего не ту в том что программа валиться. Вы неправильно работаете с потоком (обращаетесь к гую из другого потока). Все работа с гуем должна быть ТОЛЬКО в гуевом потоке (main\GUI thread).Почитайте вот это по потокам :Thread Support in Qt
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
kirill
Гость
« Ответ #2 : Ноябрь 12, 2008, 12:56 »

Если я буду вызывать webview->print() из главного потока, то получу "заморозку". Может ткнете пальцем как правильно вызвать долгоработающие функции в фоне?
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #3 : Ноябрь 12, 2008, 12:58 »

Думаю вот эта статья вам поможет: http://labs.trolltech.com/blogs/2007/09/27/multi-threaded-text-layout-and-printing/

В статье приведена печать в потоке через QTextDocument, а в вашем случае печать будет через QWebFrame (загляните в исходники QWebView::print).

Удачи Улыбающийся
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
kirill
Гость
« Ответ #4 : Ноябрь 12, 2008, 13:13 »

Спасибо за линк!
Записан
kirill
Гость
« Ответ #5 : Ноябрь 13, 2008, 08:50 »

Таки не вышло у меня сделать нормальныю печать.
Подскажите что не так.

1) Класс потока, который будет печатать:
Код:
class PrintThread : public QThread
{
   Q_OBJECT
public:
   PrintThread(QObject * parent = 0);
   void start(const QString &);
   QPrinter printer_;
   QWebPage *wpage_;
   QPrinter *printer(){return &printer_;};

protected:
   void run();
};

Это почти как в примере выше.

2) Вызываю из GUI main
Код:
   PrintThread *ptPrint = new PrintThread(this);

   QPrintDialog dlg(ptPrint->printer(), this);

   if (dlg.exec() == QDialog::Accepted)
   {
      connect(ptPrint, SIGNAL(finished()), ptPrint, SLOT(deleteLater()));
      ptPrint->start(html);
    }
   else
   {
      delete ptPrint;
   }

Тут тоже вроде все понятно.

3) Внутренности PrintThread, которые вызывают сомнения
Код:
void PrintThread::start(const QString & html)
{
   html_ = html;
   wpage_ = new QWebPage(this);
   wpage_->moveToThread(this);
   wpage_->mainFrame()->setHtml(html_);
   
   QThread::start();
}

В класс потока передается строка html, которая интерпретируется QWebPage.

4) Печать в потоке
Код:
void PrintThread::run()
{
   wpage_->mainFrame()->print(&printer_);
}

В итоге это не работает. То есть иногда работает, когда немного надо печатать, но для большого документа выдает чистый лист и все. И иногда валится с ошибкой.
Что за коряга такая непонятно.

Подскажите что не так то?

ЗЫ
Исследуя QWebPage обнаружил, что его setHtml непонятно работает. Такое ощущение, что она завершает работу не успев загрузить весь html. Так вот у QwebPage есть сигнал loadFinished(bool), который сигнализирует об окончании загрузки документа. Но прикрутить его к слоту потока не вышло. Я хотел в start потока поставить коннект connect(wpage_, SIGNAL(loadFinished(bool)), this, SLOT(loaded(bool))) прописав с класс потока слот loaded и на его срабатывание запускать QThread::start(). Однако слот не срабатывает.
« Последнее редактирование: Ноябрь 13, 2008, 08:57 от kirill » Записан
BRE
Гость
« Ответ #6 : Ноябрь 13, 2008, 10:08 »

А попробуй  в классе объявить QWebFrame *wframe_;
и сделать так:
Код:
void PrintThread::start(const QString & html)
{
   html_ = html;
   wpage_ = new QWebPage(this);
   wframe_ = wpage_->mainFrame();
   wframe_->setHtml(html_);
   wframe_->moveToThread( this );

   QThread::start();
}

void PrintThread::run()
{
   wframe_->print(&printer_);
}

Записан
kirill
Гость
« Ответ #7 : Ноябрь 13, 2008, 10:49 »

Попробовал, та же фигня.
Маленькие документы печатает, а на большие выдает 1 чистый лист.
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #8 : Ноябрь 13, 2008, 12:50 »

А если попробывать так:

Код:
class PrintThread : public QThread
{
    QPrinter _printer;
    QWebFrame *_frame;

public:
    PrintThread(QObject *parent)
        : QThread(parent), _printer(QPrinter::HighResolution), _frame(0)
    {
    }
    ~PrintThread()
    {
        wait();
    }

    QPrinter *printer()
    {
        return &_printer;
    }

    void start(const QString &html)
    {
        _frame = new QWebFrame();     //парент не указываем!
        _frame->moveToThread(this);
        _frame->setHtml(html);
        QThread::start();
    }

protected:
    void run()
    {
        _frame->print(printer());
        delete _frame;
        _frame = 0;
    }
};


void <some_class>::print()
{
    if (!QFontDatabase::supportsThreadedFontRendering()) {
        QPrinter printer(QPrinter::HighResolution);

        QPrintDialog dlg(&printer, this);
        if (dlg.exec() == QDialog::Accepted) {
            qApp->setOverrideCursor(Qt::WaitCursor);
            _webView->print(&printer);
            qApp->restoreOverrideCursor();
        }
        return;
    }

    PrintThread *thread = new PrintThread(this);

    QPrintDialog dlg(thread->printer(), this);
    if (dlg.exec() == QDialog::Accepted) {
        connect(thread, SIGNAL(finished()), SLOT(printingFinished()));
        connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

        qApp->setOverrideCursor(Qt::BusyCursor);
        thread->start(_webView->page()->mainFrame()->toHtml());
    } else {
        delete thread;
    }

}

void <some_class>::printingFinished()
{
    qApp->restoreOverrideCursor();
}

где _webView - это чден класса <some_class>.
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
kirill
Гость
« Ответ #9 : Ноябрь 13, 2008, 15:30 »

Попробую конечно, спасибо.

Но вот сразу вопрос - QWebFrame имеет закрытый конструктор.
Явно к нему обратиться нельзя. Оперировать похоже надо через QWebPage, он наследует от QObject и вроде не является GUI.
Выше BRE приводил пример обращения к QWebFrame.

А в остальном код сильно похож на qt/tools/assistant/compat/mainwindow.cpp
Я его ковырял, но подстроить под себя не удалось.

ЗЫ
Жаль троли не написали функции backgroundPrint()
« Последнее редактирование: Ноябрь 13, 2008, 15:33 от kirill » Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #10 : Ноябрь 13, 2008, 15:46 »

Попробую конечно, спасибо.

Но вот сразу вопрос - QWebFrame имеет закрытый конструктор.
Явно к нему обратиться нельзя. Оперировать похоже надо через QWebPage, он наследует от QObject и вроде не является GUI.
Выше BRE приводил пример обращения к QWebFrame.

Да, быть может. Код я не пытался компилировать, писал прямо на форуме

А в остальном код сильно похож на qt/tools/assistant/compat/mainwindow.cpp
Я его ковырял, но подстроить под себя не удалось.

собственно говоря от туда и есть Улыбающийся

ЗЫ
Жаль троли не написали функции backgroundPrint()

По этому поводу вы можите написать suggestion тролям: http://trolltech.com/bugreport-form
будет весьма полезная фича Улыбающийся


В пердыдущих листингах вы создавали QWebPage, указав ему парент

Цитировать
wpage_ = new QWebPage(this);

потом вы перемещаете его в другой поток. А так делать нельзя. Я незря поставил коментарий в своем листинге. Возможно проблема связанна именно с этим.

Цитировать
void QObject::moveToThread ( QThread * targetThread )
Changes the thread affinity for this object and its children. The object cannot be moved if it has a parent. Event processing will continue in the targetThread.
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.121 секунд. Запросов: 23.