In the two previous blog posts we have learned how to query a layer tree and how to modify it.All these new APIs are available since QGIS 2.4 release.Today we will look into how to make layer trees available in GUI and connect them with a map canvas.
As we have seen earlier, a layer tree is a usual hierarchical data structure composed from nodes of twotypes - layers and groups. They do not provide any GUI functionality as they live in the QGIS core library.In order to visualize a layer tree, we will use Model/View approach from Qt framework. Readers not familiarwith those concepts are recommended to read the Qt Model/View overview first.
There is QgsLayerTreeModel
class (derived from QAbstractItemModel
) which as you may have guessed providesa model to access a layer tree. Instance of this class may be used in any QTreeView
class, howeverit is recommended to use it together with QgsLayerTreeView
because of the extra convenience functionalityofferred by the custom view class.
Here is an example how to create another view of current project's layer tree (try that in QGIS Python console):
from qgis.gui import *
root = QgsProject.instance().layerTreeRoot()
model = QgsLayerTreeModel(root)
view = QgsLayerTreeView()
view.setModel(model)
view.show()
Any changes that happen to the layer tree structure are automatically monitored by the model/view classes.After running the example above, try changing a layer's name or add/remove/reorder some layers - allthose actions will be immediately visible in all views.
As you can see, the layer tree view is just one way how to visualize the underlying layer tree - in the futureit may be possible to have different ways to show the layer tree, for example using Qt's QML framework(with all sorts of animated transitions known from mobile apps).
Plugin developers can access the layer tree view in the main window of QGIS through the following interface call:
view = iface.layerTreeView()
The model is meant to be flexible and it is possible to use it in various contexts. For example,by default the model also provides legend for the layers in the tree. This however may not be wantedin some cases. Similarly, sometimes the layer tree should be read-only while in other context it isdesired that the user can reorder layers or change their names. These preferences can be passed tothe model with flags:
model = QgsLayerTreeModel(root)
model.setFlag(QgsLayerTreeModel.AllowNodeReorder)
model.setFlag(QgsLayerTreeModel.AllowNodeChangeVisibility)
The setFlag()
method has optional second parameter "enabled" (True
by default). Flags can be alsoset all at once with setFlags()
method which expects a combination of flags joined by binary OR operator.There are also flags()
and testFlag()
methods to query the current flags.
The QgsLayerTreeModel
class also provides routines for conversion between QgsLayerTreeNode
instancesand corresponding QModelIndex
objects used by Qt Model/View framework - index2node()
and node2index()
may come handy especially when working with views.
There is also some functionality related to legend display - it has been greatly extended in QGIS 2.6 releaseand we will try to cover that in a future blog post.
As mentioned earlier, it is possible to use any QTreeView
instance in combination with QgsLayerTreeModel
to show the layer tree, but it is highly recommended to use QgsLayerTreeView
class (a subclass of QTreeView
)because of the additional functionality it provides (and more may be added in the future):
QgsLayerTreeView
class adds higher level methods that operate with QgsLayerTreeNode
objects like currentNode()
or with QgsMapLayer
objects like currentLayer()
.QgsLayerTreeViewMenuProvider
) - its createContextMenu()
implementation will return a QMenu
object with custom actions whenever user right-clicks in the view. Additionally, there is a factory class QgsLayerTreeViewDefaultActions
that can create commonly use actions for use in the menu, such as "Add Group", "Remove" or "Zoom to Layer". The following example shows how to create a provider with one action that shows the current layer's extent:def createContextMenu(self):
if not self.view.currentLayer():
return None
m = QMenu()
m.addAction("Show Extent", self.showExtent)
return m
def showExtent(self):
r = self.view.currentLayer().extent()
QMessageBox.information(None, "Extent", r.toString())
The layer tree classes and map canvas class are separate components that are not dependent on each other.This is a good thing and a great step forward, because until QGIS 2.2 there was big internal monolithicQgsLegend
view class that handled everything and it was directly connected to map canvas and various othercomponents, making it impossible to reuse it elsewhere. With the new layer tree API this has been solved,now it is possible use map canvas without an associated layer tree view or vice versa - to use alayer tree view without map canvas. It is even possible to get creative and use one layer tree with severalmap canvas instances at once.
Layer tree and map canvas can be connected via QgsLayerTreeMapCanvasBridge
class. It listens to signalsfrom the given layer tree hierarchy and updates canvas accordingly. Let's see how we could create a newmap canvas that would show the same layers as the main canvas does:
canvas = QgsMapCanvas()
root = QgsProject.instance().layerTreeRoot()
bridge = QgsLayerTreeMapCanvasBridge(root, canvas)
canvas.zoomToFullExtent()
canvas.show()
That's it! We have tied the new canvas with project's layer tree. So any actions you do in the layer tree view(for example, add or remove layers, enable or disable layers) are automatically passed to the new canvas.And of course this does not work just with project's layer tree - you could use any custom layer treein your layer tree model/view or canvas.
The bridge class has advanced functionality worth mentioning. By default the ordering of layers in canvasis according to the order in the layer tree (with first layer in the tree being at the top), thoughthere are API methods to override the default order.
For convenience, the bridge by default also configures some settings of the canvas (this can be disabled if necessary):
I hope you have enjoyed the three blog posts introducing QGIS layer tree API. They should covereverything you need to know in order to start using the new functionality. In a future post we willhave a look at the new legend API that nicely complements the layer tree API - stay tuned!
Let's make the QGIS work for you
Lutra Consulting is a QGIS-focused expert provider of geospatial software development, consulting, training, and support services.