Navigation Menu

Skip to content

Commit

Permalink
Hopefully fix #10599 (blank composer map when rendering rasters)
Browse files Browse the repository at this point in the history
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.
11 changes: 11 additions & 0 deletions python/core/qgsmaprendererjob.sip
Expand Up @@ -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();

Expand Down
7 changes: 4 additions & 3 deletions src/core/composer/qgscomposermap.cpp
Expand Up @@ -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 )
Expand Down
17 changes: 17 additions & 0 deletions src/core/qgsmaprendererjob.cpp
Expand Up @@ -182,6 +182,7 @@ QgsMapRendererCustomPainterJob::QgsMapRendererCustomPainterJob( const QgsMapSett
, mPainter( painter )
, mLabelingEngine( 0 )
, mActive( false )
, mRenderSynchronously( false )
{
QgsDebugMsg( "QPAINTER construct" );
}
Expand Down Expand Up @@ -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() ) );

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


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


void QgsMapRendererCustomPainterJob::futureFinished()
{
mActive = false;
Expand Down
12 changes: 12 additions & 0 deletions src/core/qgsmaprendererjob.h
Expand Up @@ -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();

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

bool mActive;
LayerRenderJobs mLayerJobs;
bool mRenderSynchronously;
};


Expand Down

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.