You are here:GeoTux»Geo-Blogs»Libraries for Geomatics»Layer list widget for PyQGIS applications

Statistics

Invitados: 86
Usuarios registrados: 3214
Usuarios en línea:
-
Registrados hoy:
-

Register

RSS

Blogs and News:
Recibe las actualizaciones en Geo-Noticias y Geo-Blogs

Get them by e-mail
Recibir Geo-Noticias y Geo-Blogs por e-mail

¿What is this about?

Tuesday, 18 January 2011 06:01

Layer list widget for PyQGIS applications

Written by  German Carrillo
Rate this item
(4 votes)
QGIS provides several utilities for Python developers. However, if you want to build your own PyQGIS application, you have to create some widgets on your own. The layer list widget is one of them and it certainly is a must for GIS applications. Here is mine.

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: 

PyQGIS layer list widget

 

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  

 

Layer properties dialog

 

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!

 

Last modified on Wednesday, 28 September 2011 21:07

comments  

 
0 # Traducción al rusotuxman 2011-02-25 22:52
El equipo de GIS-LAB ha publicado hoy un artí­culo en ruso basado en este post. Puede ser consultado en este enlace:
http://gis-lab.info/qa/qgis-legend.html (gis-lab.info/qa/qgis-legend.html)
Reply | Reply with quote | Quote
 
 
0 # GIS analystpierre sylvain 2012-05-30 15:45
Hello,

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
Reply | Reply with quote | Quote
 
 
0 # Re:tuxman 2012-06-07 21:10
Hi,

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
Reply | Reply with quote | Quote
 
 
0 # GIS analystpierre sylvain 2012-06-13 13:32
You’re right !
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
Reply | Reply with quote | Quote
 
 
0 # Re:tuxman 2012-06-13 17:31
Hi Pierre,

I recall I did something like that this way:

object.__class__ = AnotherClass

Please consider sharing your work. :roll:

Regards,

Tuxman
Reply | Reply with quote | Quote
 
 
-1 # GIS analystpierre sylvain 2013-02-14 14:18
Hello,
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…
Reply | Reply with quote | Quote
 
 
0 # Add two layers to canvasBarbara Duarte 2016-01-07 14:32
Hello.
Congratulations for your plugin. It is very useful for me.
But I have a doubt related with more than one layer added and their visualization in map canvas. I had one layer and it is every ok (I didn't use all the properties of the plugin). But when I add a new layer, this opens in my map canvas and the first one disappear. So in the legend I have two layers and only one in map canvas. I just want you to explain which funtion deals with this and if I have to do something else in my main code.

Hope that you helps me. Thank you.

Best regards.
Reply | Reply with quote | Quote
 
 
+1 # Re:tuxman 2016-01-07 16:12
Hi Barbara,

thanks! You don't need this component anymore, because QGIS (thanks to Martin Dobias) now gives us a Layer Tree View, have a look at: http://bit.ly/1GJlVkN and tell me if there is something unclear to you.

Regards,

Tuxman
Reply | Reply with quote | Quote
 
 
0 # Add two layers to canvas - actionsBarbara Duarte 2016-01-15 15:14
Hi tuxman,

thank you so much for the answer. I try and I get it!! Now my layers are in correct order. But I miss other widgets that I would like to have in my application. For example, the possibility of zoom extent and to remove the layer (by clicking with the right button of the mouse in the layer, as actions). This actions belongs to legend.py but know I am not able to do that. Can you help please?
Tahnk you.

Beste regards,
Lia Duarte
Reply | Reply with quote | Quote
 
 
0 # Re:tuxman 2016-01-22 13:52
Hi Barbara,

please have a look at the documentation of the QgsLayerTreeVie w [1], specifically at the bullet point "Display of context menu."

You'll find there indications on how to implement your own context menu, as well as an example. Please give it a try; if I remember well, when I gave it a try it didn't work for me. If that's the case also for you, we could file a ticket reporting the issue.

If you have success, please tell me how you achieved it :)

Regards,

Tuxman
----
[1] http://www.lutraconsulting.co.uk/blog/2015/01/30/qgis-layer-tree-api-part-3/
Reply | Reply with quote | Quote
 
 
0 # Add two layers to canvasBarbara Duarte 2016-01-22 22:36
Hi tuxman,

It works!!! :) Thank you so much, it was very very useful this help.

Thank you for all the help.
Best regards,
Lia Duarte
Reply | Reply with quote | Quote
 
 
0 # Re:tuxman 2016-01-22 23:35
Glad you found it useful, Barbara.
BTW, we publish tips like this in our Twitter account: twitter.com/GeoTux2 Follow us there!

Regards,

Tuxman
Reply | Reply with quote | Quote
 

Add comment


Security code
Refresh

 

On-line users