I have created a widget for PyQGIS applications that is a (really) simplified version of the QGIS layer list widget. The main difference is that it has no group layers. The widget is also based on OpenOceanMap's legend written by Aaron Racicot but instead of working with QCheckBox controls it uses QTreeWidgetItem for representing every map layer.
This is a screenshot of what you may get:

What does the widget allow?
- Get an ordered list of map layers.
- Move up or down a layer affecting its z-order in the map.
- Make a layer visible or invisible in the map.
- Visualize/change the layer symbology (actually, you have to develop your own layer symbology dialog, I just give you a foo example).
- Change some layer properties.
- Load/Save QGIS layer style files.
- Remove layers.
- Integrate your map with other tools acting over loaded layers (e.g. Show/Hide all, Remove all).
What about the license?
It is GNU GPL v.2.
How to include it?
To include the widget on your PyQGIS application you should follow these steps:
1. Download this ZIP file and extract it to your application folder. It contains the legend.py file, which is actually the widget, a number of images (icons) to represent layer types and menu options, and finally, a dialog that is used to set layer properties.
You can get the icons from the QGIS project, I have not created them.
2. Import the Legend class.
In the main class of your application, which inherits from QMainWindow, import the Legend class from the legend.py file, this way:
from legend import Legend
3. Add the CreateLegendWidget method.
Include the CreateLegendWidget method in the main class of the application to add the dock widget into the GUI and associate the layer list widget to the canvas. The method is this:
def createLegendWidget( self ):
""" Create the map legend widget and associate to the canvas """
self.legend = Legend( self )
self.legend.setCanvas( self.canvas )
self.legend.setObjectName( "theMapLegend" )
self.LegendDock = QDockWidget( "Layers", self )
self.LegendDock.setObjectName( "legend" )
self.LegendDock.setAllowedAreas( Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea )
self.LegendDock.setWidget( self.legend )
self.LegendDock.setContentsMargins ( 9, 9, 9, 9 )
self.addDockWidget( Qt.LeftDockWidgetArea, self.LegendDock )
In the __init__ method of the application main class call the just added method:
self.createLegendWidget() # Create the legend widget
4. Compile/Import a resource file to include legend widget icons.
The layer list widget include some icons you would like to see. To accomplish this, compile the provided resources.qrc file with the following command:
$ pyrcc4 resources.qrc -o resources_rc.py
The legend.py file already contains a reference to the genereated file. Nevertheless, if you have your own resources file, you may add all the images in the imgs folder into a new prefix, for instance, "legend". If you want to choose another prefix, make sure to change the resource_prefix variable in the legend.py file as well.
resources_prefix = ":/legend/imgs/"
5. Let the legend to load and remove layers in order to avoid segmentation fault.
You must have a method to load layers into your map application, but now that you want to include a layer list widget you should let it control all these matters. The layer list widget has a SLOT to manage the layer set at the time you load, move or remove a layer. All you have to do is to call the appropriate methods (either addMapLayer or removeMapLayer) from QgsMapLayerRegistry instance, but do not use the setLayerSet canvas method yourself, the new widget will. So, comment or delete your setLayerSet calls.
QgsMapLayerRegistry.instance().addMapLayer( layer );
#self.canvas.setLayerSet( self.layers )
6. Load the properties dialog.
To allow the user set some layer properties you have to compile the dlgLayerProperties.ui file, which will provide a basic dialog.
$ pyuic4 dlgLayerProperties.ui -o dlgLayerProperties_ui.py

7. (Optional) Enable/Disable tools
The layer list widget emits a SIGNAL that allows you to enable/disable tools in your application, according to the active layer type, either raster or vector. The SIGNAL is called activeLayerChanged and if you want to use it, you are suppose to write something like this in your application main class:
self.connect( self.legend, SIGNAL( "activeLayerChanged" ),
self.enableTools )
... # Probably more code
def enableTools( self ):
if not self.legend.activeLayer():
# Disable some general tools
else:
# Enable some general tools
layerType = self.legend.activeLayer().layer().type()
if layerType == 0: # Vector Layer
# Enable vector tools and disable others
elif layerType == 1: # Raster Layer
# Enable raster tools and disable others
8. (Optional) Use a few Legend class methods to expose functionality to other tools or plugins:
- Iterate over the layers:
for layer in self.legend.layers:
...
- Show (or hide) all the layers in the map:
def showAllLayers( self ):
self.legend.setStatusForAllLayers( True )
- Get the active layer (for plugins):
return self.legend.activeLayer()
- Refresh the layer symbology (for plugins):
self.legend.refreshLayerSymbology( layer )
- Remove layers by Id (for plugins):
self.legend.removeLayers( layerIds )
That's it!









comments
http://gis-lab.info/qa/qgis-legend.html (gis-lab.info/qa/qgis-legend.html)
I'm developping a Python application and i'm using your devs. Great job!
I get some trouble with vectorLayerSymb ology method:it seems that the renderer is not convenient.
Line: renderer = layer.renderer()
AttributeError: 'NoneType' object has no attribute 'symbols'
So I have to use rendererV2, and rendererV2 doesn't support getPointSymbolA sImage method...
Do you have any idea to fix it?
Thanks
glad you find it useful.
The problem you have now is related to this legend's lack of support for symbology-ng (new generation) in QGIS.
You can replace the functions of this file [1] (in legend.py) to have single symbology-ng working, but not categorized nor graduated I guess.
Most of the functionality in this legend is adapted from [2] (in C++), so if you can deal with a bit of C++ code and adapt it to Python, please let me know, we could work enabling this legend to support symbology-ng. In that case I would set up a SVN repository for the code.
Regards,
Tuxman
---------
[1] http://downloads.tuxfamily.org/tuxgis/geoblogs/pyqgis_toc/functions_to_replace.py
[2] https://raw.github.com/qgis/Quantum-GIS/master/src/app/legend/qgslegendlayer.cpp
During last days I’ve found a solution looking into cpp code.
Now it works. But I think code is not realy clean (I’m a Python newby !) The next step for me : legend group !
The first question is : create a new class Legendgroup like LegendItem or as a subclass of legendItem ?
I look at C++ and try to "translate" into Python.
But I got a problem to give a type to QTreeWidgetItem s, I don't know the way to write such lines:
QgsLegendItem *litem = dynamic_cast( item );
QgsLegendGroup *group = dynamic_cast( item );
QgsLegendLayer *layer = dynamic_cast( item );
Regards
I recall I did something like that this way:
object.__class__ = AnotherClass
Please consider sharing your work.
Regards,
Tuxman
I'm back!
Work is going on, and I have much more question specialy if I compare legend.py to QGis legend behaviour:
In QGis when you check on or off a layer, only these one is redraw not all other.
That’s not the legend.py behaviour now.
What should be the best way to do this inside legend.py?
PS: I didn't forget your proposal to share my dev, but at this moment it is embeded inside my app, so hard to share, but…
RSS feed for comments to this post