Skip to content
Permalink
Browse files
Hopefully fix #10599 (blank composer map when rendering rasters)
When printing on Windows, the printing does not seem to work
well in the worker thread as QImages get converted to QPixmaps.
Therefore we force the map rendering into main thread to avoid the issues.

I do not have a printer, so I can't confirm the fix really helps
  • Loading branch information
wonder-sk committed Jun 20, 2014
1 parent 98959bb commit 7aa93c0
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 3 deletions.
@@ -218,6 +218,17 @@ class QgsMapRendererCustomPainterJob : QgsMapRendererJob
*/
void waitForFinishedWithEventLoop( QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents );

/**
* Render the map synchronously in this thread. The function does not return until the map
* is completely rendered.
*
* This is an alternative to ordinary API (using start() + waiting for finished() signal).
* Users are discouraged to use this method unless they have a strong reason for doing it.
* The synchronous rendering blocks the main thread, making the application unresponsive.
* Also, it is not possible to cancel rendering while it is in progress.
*/
void renderSynchronously();

protected slots:
void futureFinished();

@@ -221,9 +221,10 @@ void QgsComposerMap::draw( QPainter *painter, const QgsRectangle& extent, const

// render
QgsMapRendererCustomPainterJob job( jobMapSettings, painter );
job.start();
// wait, but allow network requests to be processed
job.waitForFinishedWithEventLoop( QEventLoop::ExcludeUserInputEvents );
// Render the map in this thread. This is done because of problems
// with printing to printer on Windows (printing to PDF is fine though).
// Raster images were not displayed - see #10599
job.renderSynchronously();
}

void QgsComposerMap::cache( void )
@@ -182,6 +182,7 @@ QgsMapRendererCustomPainterJob::QgsMapRendererCustomPainterJob( const QgsMapSett
, mPainter( painter )
, mLabelingEngine( 0 )
, mActive( false )
, mRenderSynchronously( false )
{
QgsDebugMsg( "QPAINTER construct" );
}
@@ -237,6 +238,13 @@ void QgsMapRendererCustomPainterJob::start()

QgsDebugMsg( "Rendering prepared in (seconds): " + QString( "%1" ).arg( prepareTime.elapsed() / 1000.0 ) );

if ( mRenderSynchronously )
{
// do the rendering right now!
doRender();
return;
}

// now we are ready to start rendering!
connect( &mFutureWatcher, SIGNAL( finished() ), SLOT( futureFinished() ) );

@@ -311,6 +319,15 @@ void QgsMapRendererCustomPainterJob::waitForFinishedWithEventLoop( QEventLoop::P
}


void QgsMapRendererCustomPainterJob::renderSynchronously()
{
mRenderSynchronously = true;
start();
futureFinished();
mRenderSynchronously = false;
}


void QgsMapRendererCustomPainterJob::futureFinished()
{
mActive = false;
@@ -278,6 +278,17 @@ class CORE_EXPORT QgsMapRendererCustomPainterJob : public QgsMapRendererJob
*/
void waitForFinishedWithEventLoop( QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents );

/**
* Render the map synchronously in this thread. The function does not return until the map
* is completely rendered.
*
* This is an alternative to ordinary API (using start() + waiting for finished() signal).
* Users are discouraged to use this method unless they have a strong reason for doing it.
* The synchronous rendering blocks the main thread, making the application unresponsive.
* Also, it is not possible to cancel rendering while it is in progress.
*/
void renderSynchronously();

protected slots:
void futureFinished();

@@ -296,6 +307,7 @@ class CORE_EXPORT QgsMapRendererCustomPainterJob : public QgsMapRendererJob

bool mActive;
LayerRenderJobs mLayerJobs;
bool mRenderSynchronously;
};


3 comments on commit 7aa93c0

@nyalldawson
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wonder-sk this seems a bit unfortunate.. Do you think it would be possible to render synchronously only when printing, so that interactions with composer maps remains quick? We could do this via a setting for the composer map (setRenderSynchronously) or via a composition property (forceSynchronousRendering) which is true only when printing?

@wonder-sk
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nyalldawson It should be still possible to have asynchronous rendering when drawing on screen.

The code in composer right now cannot take advantage of the background rendering anyway - it will require some more code changes to handle it nicely... I.e. instead of waiting until the map is completely rendered, the redraw even will only start the rendering - and when finished, it would trigger update of composer map - similar to how it is done in map canvas.

@nyalldawson
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Martin-SK Ahh, I think I misunderstood (I'm away from my computer and not able to test at the moment). I thought this change disabled multithreaded rendering too.

Please sign in to comment.