I want the user to make a selection of a layer from a QgsMapLayerComboBox and setting up their settings they wish to use. After a click on a button, a function should be called which performs the work. There are different buttons to call different functions.
I actually have a working code below, but it seems quite ridiculous to me to catch the selectedLayer
more than once. I think I am doing something completely wrong here and there must be an efficient and proper way of passing a variable from run
to a function when a button has been clicked.
I actually managed to do it as explained here, but not as expected. (I must have obviously misuderstood the answer). When using self.dlg.Isochrones_RequestIsochrones.clicked.connect(self.Isochrones_RequestIsochrones(selectedLayer))
it seems to pass the selectedLayer
to the function, but the function is beeing executed right on startup of the plugin. There is no chance for the user to make their settings.
class OpenTripPlannerPlugin:
# other stuff here
def Isochrones_RequestIsochrones(self, selectedLayer):
# I am actually doing this twice because I am not able to pass the selected layer from run properly
layers = QgsProject.instance().layerTreeRoot().children()
selectedLayerName = self.dlg.Isochrones_SelectInputLayer.currentText()
selectedLayer = [l.layer() for l in layers if l.name() == selectedLayerName][0]
# doing stuff with the selected Layer here
def run(self):
if self.first_start == True:
self.first_start = False
self.dlg = OpenTripPlannerPluginDialog()
# Using QgsMapLayerComboBox to make a layer selection
vector_names = [l.name() for l in QgsProject().instance().mapLayers().values() if isinstance(l, QgsVectorLayer)] # Fetch vector layer names
self.dlg.Isochrones_SelectInputLayer.addItems(vector_names) # Fill with layers
self.dlg.Isochrones_SelectInputLayer.setFilters(QgsMapLayerProxyModel.PointLayer) # Filter out all layers except Point layers
# Getting selectedLayer and hopefully passing it to functions
layers = QgsProject.instance().layerTreeRoot().children()
selectedLayerName = self.dlg.Isochrones_SelectInputLayer.currentText()
selectedLayer = [l.layer() for l in layers if l.name() == selectedLayerName][0] <-- I want to make this selected layer available in other functions I call
# Doing some stuff with selectedLayer like setting up QgsOverrideButton
self.dlg.Isochrones_WalkSpeed_Override.registerExpressionContextGenerator(selectedLayer)
self.dlg.Isochrones_WalkSpeed_Override.init(0, QgsProperty(), QgsPropertyDefinition("walkSpeed", "Walk Speed km/h", QgsPropertyDefinition.DoublePositive), selectedLayer, False)
# Doing more stuff...
# Calling Functions on button click
self.dlg.Isochrones_RequestIsochrones.clicked.connect(self.Isochrones_RequestIsochrones) # <-- Using ...(self.Isochrones_RequestIsochrones(selectedLayer)) seems to work, but the function is executed on startup of the plugin with no chance to make individual settings
# show the dialog
self.dlg.show()
# Run the dialog event loop
result = self.dlg.exec_()
# See if OK was pressed
if result:
#Isochrones_RequestIsochrones()
print("test!")
How do I properly pass the selectedLayer
to a function after a button has been clicked?
Best Answer
Solution 1:
When connecting a method to an object event (in this case
click
event) in PyQt, for passing an argument to that method, you can uselambda
function.After doing that, you don't need three lines in
Isochrones_RequestIsochrones
method. Because you passed the selected layer to the method. But in this case, you can't useselectedLayer
in other functions exceptIsochrones_RequestIsochrones
.Solution 2:
If you want to make
selectedLayer
available in other functions in the class, convertselectedLayer
from Local Variable to Instance Variable by addingself
keyword beforeselectedLayer
.After doing that, you don't need to pass
selectedLayer
as an argument, because you can access this variable in every instance methods (for exampleIsochrones_RequestIsochrones
) defined in the class. In this case, no needlambda
function, because no need passingselectedLayer
as argument.Also, no need those three lines in
Isochrones_RequestIsochrones
method anymore.