-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RasterLayer: Properly handle GUI updates when multiple canvas are displayed #59444
base: master
Are you sure you want to change the base?
Conversation
26595b2
to
7b17df6
Compare
🪟 Windows buildsDownload Windows builds of this PR for testing. 🪟 Windows Qt6 buildsDownload Windows Qt6 builds of this PR for testing. |
61f86be
to
33998d8
Compare
Good approach, I like where this is going! 👍 |
db19524
to
abf6011
Compare
@nyalldawson This should be ready now. |
29e68f8
to
3060e67
Compare
This will be used in the next commits to store the min-max values of a raster layer and report them to the main canvas.
This is similar to what is achieved in `QgsRasterLayer::refreshRendererIfNeeded()` to check if the renderer needs to be refresh according to an extent. It does not perform any refresh. It is not used at the moment. This will replace the logic to refresh a renderer in the following commits.
This is similar to what is achieved in `QgsRasterLayer::refreshRenderer()` to refresh the renderer according to an extent. Contrary to the first one, this method does not perform any GUI update or emit any signal. It is not used at the moment. This will replace the logic to refresh a renderer in the following commits.
This will be used in the next commit to refresh a renderer.
This replaces the existing logic in `QgsRasterLayerRenderer` which calls `QgsRasterLayer::refreshRendererIfNeeded()` to refresh the renderer associated `QgsRasterLayerRenderer` and the raster associated with `QgsRasterLayer`. It also makes GUI updates. With this approach, the following new logic is done: 1. `QgsRasterRenderer::needsRefresh()` is called to check if `rasterRenderer` needs to be updated. 2. If a refresh is needed, the new min/max values are computed by calling `QgsRasterLayer::computeMinMax()` 3. The min/max values are used to refresh `rasterRenderer` 4. The min/max values are stored in a `QgsRenderedLayerStatistics` and propagated to `QgisApp` 5. In QgisApp, `QgsRenderedLayerStatistics` is used to refresh the renderer of `QgsRasterLayer` and force a refresh of the style and the legend if the change comes from the main canvas.
This is not used anymore.
3060e67
to
a6a76a1
Compare
/** | ||
* Constructor for QgsRenderedLayerStatistics from a list of \a minimum and \a maximum. | ||
*/ | ||
QgsRenderedLayerStatistics( const QString &layerId, QList<double> minimum, QList<double> maximum ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
QgsRenderedLayerStatistics( const QString &layerId, QList<double> minimum, QList<double> maximum ); | |
QgsRenderedLayerStatistics( const QString &layerId, const QList<double>& minimum, const QList<double>& maximum ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this mean though? Can you elaborate in the docs when this would be used and what the list values represent?
{ | ||
maximums.append( QString::number( max ) ); | ||
} | ||
QString str = QStringLiteral( "<QgsRenderedLayerStatistics: %1 ([%2] x [%3])>" ).arg( sipCpp->layerId(), minimums.join( ',' ), maximums.join( ',' ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"[ ] x [ ]" is an odd choice here, that looks a bit like a matrix of values. Maybe just explicitly go "min: %2, max %3" instead?
|
||
if ( !computedStatistics.empty() ) | ||
{ | ||
for ( QgsMapLayer *layer : mMapCanvas->layers() ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be modified to loop through the statistics, and then retrieve the layer from the project by the ID from the statistics accordingly.
{ | ||
|
||
// refresh the renderer of the layer | ||
rasterLayer->renderer()->refresh( statistics->boundingBox(), statistics->minimum(), statistics->maximum() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be inside the if ( mapCanvas == mMapCanvas ) check? otherwise we'll end up changing the renderer for non-main canvas too!
Actually on that note, I don't think we should be calling handleRenderedLayerStatistics at ALL for non-main canvases.
* | ||
* \since QGIS 3.42 | ||
*/ | ||
virtual bool refresh( const QgsRectangle &extent, const QList<double> &min, const QList<double> &max, bool forceRefresh = false ) override SIP_SKIP; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
virtual bool refresh( const QgsRectangle &extent, const QList<double> &min, const QList<double> &max, bool forceRefresh = false ) override SIP_SKIP; | |
bool refresh( const QgsRectangle &extent, const QList<double> &min, const QList<double> &max, bool forceRefresh = false ) override SIP_SKIP; |
* | ||
* \since QGIS 3.42 | ||
*/ | ||
virtual bool refresh( const QgsRectangle &extent, const QList<double> &min, const QList<double> &max, bool forceRefresh = false ) override SIP_SKIP; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
virtual bool refresh( const QgsRectangle &extent, const QList<double> &min, const QList<double> &max, bool forceRefresh = false ) override SIP_SKIP; | |
bool refresh( const QgsRectangle &extent, const QList<double> &min, const QList<double> &max, bool forceRefresh = false ) override SIP_SKIP; |
Much cleaner, this is great! 💯 |
Looks good 👍 This approach will be useful for MeshLayer as well. |
Description
This fixes an issue mentioned by @nyalldawson in qgis/QGIS-Enhancement-Proposals#273
This occurs when the Min/Max settings is set in the renderer and multiple canvas are displayed. Indeed, in that case
QgsRasterLayer
updates the GUI (the renderer widget and the legend) multiple times when the rendered values are updated because each canvas causes a renderer update.This issue is fixed by removing the GUI update from the raster layer code. With this change, when the rendered values are updated, these statistics (min-max) are propagated to the canvas by the use of a
QgsRenderedItemDetails
:QgsRenderedCalculatedResults
. Then, only the main canvas is notified of this change and updates the GUI accordingly.