Is there is a signal in QGIS emitted when a project is about to be closed (QGIS closing or some other project opening)?
I want to programmatically save changes in layers if they are in edit mode.
I did not find it.
There is a "cleared" signal in QgsProject but fires after the project is closed.
QgsMapLayer has a "willBeDeleted" signal but also fires after system prompts the save dialog.
Not completely sure what you're asking as QGIS automatically prompts the user if they want to save layers which are in editing mode. But the following code can be used which saves all layers currently in edit mode:
for layer in QgsMapLayerRegistry.instance().mapLayers().values():
layer.commitChanges()
If you have several options, you can combine them for different cases:
You can use QgsProject signals.
You have the signal cleared()
but as @Jaume Figueras points out it runs after closing.
You can complement it with projectSaved()
signal when the user during the execution clicks on save.
Since you are interested in saving the changes of the layers by code, it would be best to focus on them with.
The QgsProject signal, layersWillBeRemoved()
, when closing the project is triggered before removing the layers.
But I think the ideal option is to use the signals on the layers (QgsMapLayer
), specifically willBeDeleted ()
.
As the API indicates:
Emitted in the destructor when the layer is about to be deleted, but it is still in a perfectly valid state: the last chance for other pieces of code for some cleanup if they use the layer.
To connect the events on the layers you can generate a list of all the layers and with a cycle connect the signal:
pry= QgsProject.instance() #Capture the project
listLayers= list(pry.mapLayers().values())
for i in listLayers:
i.willBeDeleted.connect(self.your_function)
To connect and disconnect the signals to the layers that are added and removed during execution you use the QgsProject
signals, layersWillBeRemoved
, layersAdded
, among others
willBeDeleted
(and other) signal.
Commented
Sep 15, 2020 at 14:16
The signal QgsProject.instance().layersWillBeRemoved
is emitted whenever one or more layers are about to be removed.
The associated slot will get the list of layer ids, providing access to the layer data:
class xxx (object):
def layers_will_be_removed(self, layer_ids: list):
for id in layer_ids:
try:
layer = QgsProject.instance().mapLayer(id)
layer_name = layer.name()
message = "Ok"
except Exception as e:
message = e
QMessageBox.information(self.iface.mainWindow(), "Warning", f"Closing {layer_name}, {has_changes}")
def __init__(self):
QgsProject.instance().layersWillBeRemoved.connect( self.layers_will_be_removed )
As said in the comment, when the function associated to willBeDeleted
the layer is already deleted; while you could put into the lambda the layer name, you would be unable to get the layer itself and its data.