Notes on SpatiaLite, QGIS and PyQt
19.05.2012 11:21 · GIS, Notes · tips
We all face problems from time to time. Here are a few recent ones from my personal collection.
QGIS and SpatiaLite
Those who build QGIS themselves know that not so long ago there was a move to use external spatialindex and SpatiaLite instead of internal bundled copies. The former has been completely removed, but SpatiaLite is still there because it is either missing or too old in some distributions (namely Debian Squeeze, as well as Ubuntu Lucid, Maverick, Natty and Oneiric). The problem occurs when building QGIS with an external version of the library.
For historical reasons, the SpatiaLite can be compiled in two different ways:
- as a loadable extension module for the system version of SQLite
- as a standalone all-in-one library that combines the SQLite engine with the spatial capabilities of SpatiaLite
So. If you have SpatiaLite built as an all-in-one library, you can kiss SpatiaLite support in QGIS goodbye. You will not be able to create a new layer or open an existing one. What spices things up is that both configuration and compilation go smoothly: no missing files, no errors. The solution is to rebuild SpatiaLite as a loadable module and then rebuild QGIS. However, at this point you may face another problem.
SpatiaLite and dynamic linker
If the configure
script constantly fails to find SQLite, GEOS and PROJ.4 when building a loadable SpatiaLite module on Linux, even though all these libraries are installed and have the correct version number, it is likely that your distribution has a policy of using unmodified source code (i.e., sources are only patched when absolutely necessary).
It should help to run configure
as shown below
LDFLAGS=-ldl ./configure
PyQt4 and a new style of signal-slot connections
Since PyQt 4.5 there is a “new” style of signal-slot connection available in addition to the old style (more details). The new style is more Pythonic, and it is highly recommended to use it instead of the old style. The only thing is… if the interface was generated in Qt Designer and then converted to code using pyuic4
, and the new style signal-slot connections are used in the code, then when you try to disconnect the signal from the slot, you may get a message that the operation cannot be performed. The situation has been clarified after contacting the developers:
PyQt allows connections to be made to any Python callable.
With old style connections a proxy slot is created under the covers whenever a callable is used (as opposed to when SLOT() is used to refer to a C++ slot). Therefore, in your example, a proxy is always created for the connection to Dialog.reject even though that refers to the object that wraps the C++ slot (as there is no Python reimplementation of reject()).
New style connections are a bit smarter in that they treat slot objects that refer to a wrapped C++ slot and objects that refer to some real Python code differently – a proxy is only created in the latter case.
So the rule is that if you make a connection old style then you must disconnect old style as well and the same for new style. You also need to be aware that pyuic4 uses old style connections.
It’s actually a bug, but they won’t fix it.
I accept that this is a bug, but I don’t want to fix it. The reason is that the changes required to the old style support code would be quite significant and I don’t think the risk to the stability of that code is worth it at this stage of the life of PyQt4 particularly as the workaround is straightforward.
The mentioned workaround is to create a dummy slot that simply calls the corresponding slot of the parent object. I.e., if you wanted to disconnect the reject()
slot of a dialogue from the rejected()
signal, using the old style, it was enough to write
QObject.disconnect(self.buttonBox, SIGNAL("rejected()"), self.reject)
and it didn’t matter whether reject()
was implemented in your dialogue or not. However, if you are using a new style, you must implement reject()
def reject(self):
QDialog.reject(self)