I've used the Plugin Builder tool to create the template python code. In QT Designer I have added a QgsMapLayerComboBox and QgsFieldComboBox
I have gone through a couple of tutorials and checked the forums (ex How to connect QgsMapLayerComboBox to QgsDataDefinedButton ; How to use QgsFieldComboBox in building QGIS plugin and Populating ComboBox with unique features in selected attribute field using PyQGIS) and also looked at some existing plugins but can't work out how.
I have connected a normal combo box successfully using https://www.youtube.com/watch?v=nWKyRDxUIrI
The simple code I want to create a plugin to use in model builder is below. Comments indicate what I want as fields in the plugin.
import operator, datetime, re
in_layer_nm='t1' # Selected dataset from canvas or file system
attrib_n='Log Reason' #Attribute list from chosen dataset
regex_s=r'(Heartbeat|End)' # Regex code for search
out_val=feat['Transmission Delay(s)'] # new value -- use feat['column name'] to use a specific column or create custom value
def UpdateRecord(f,fieldName,ntext):
in_layer.startEditing()
FieldIndex = feat.fields().indexFromName(fieldName)
in_layer.changeAttributeValue(feat.id(), FieldIndex, ntext)
in_layer.commitChanges()
in_layer = QgsProject().instance().mapLayersByName(in_layer_nm)[0]
fids = []
feats = [f for f in in_layer.getFeatures()]
for feat in feats:
name = feat[attrib_n]
print (name)
if name != NULL:
if len(re.findall(regex_s, name))>0:
UpdateRecord(feat,attrib_n,out_val)
I haven't added the text fields to the plugin layout yet as I first need to resolve the connection between the chosen dataset and choosing the attribute column.
I have tried the following in the plugin _dialog.py file that's created by the Plugin Builder tool and it works if I use a normal combo box but not the QgsFieldComboBox and I prefer to use that as it seems to be dedicated for this purpose.
import os
from qgis.PyQt import uic
from qgis.PyQt import QtWidgets
from qgis.PyQt.uic import loadUiType
from qgis.PyQt.QtWidgets import QDialog, QAbstractItemView, QTableWidget, QTableWidgetItem
from qgis.PyQt.QtCore import Qt, QThread, QEvent, QCoreApplication
from qgis.core import QgsVectorLayer, Qgis, QgsProject, QgsWkbTypes, QgsMapLayer, QgsFields, QgsExpressionContextUtils
# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
FORM_CLASS, _ = uic.loadUiType(os.path.join(
os.path.dirname(__file__), 'search_update_dialog_base.ui'))
class Search_UpdateDialog(QtWidgets.QDialog, FORM_CLASS):
def __init__(self, parent=None):
"""Constructor."""
super(Search_UpdateDialog, self).__init__(parent)
self.setupUi(self)
#ref https://www.youtube.com/watch?v=KQ8mOpVQ62w&t=235s
self.pbPrint.clicked.connect(self.onpbPrint_text_Clicked) #run thepbPrint module when button is pressed
self.mMapLayerCB.layerChanged.connect(self.load_fields) #run the load_fields def when the layer is chosen
self.mFieldCB.currentIndexChanged.connect(self.load_text_values)
def layerSelected(self):
'''The user has made a selection so we need to initialize other
parts of the dialog box'''
self.initFieldList()
def initFieldList(self):
selectedLayer = self.mMapLayerCB.currentIndex()
# self.mFieldCB.clear()
# self.mFieldCB.addItem(tr('<All Fields>'))
def updateLayers(self):
'''Called when a layer has been added or deleted in QGIS.
It forces the dialog to reload.'''
# Stop any existing search
self.killWorker()
if self.isVisible() or len(self.results) != 0:
self.populateLayerListComboBox()
self.clearResults()
self.layers_need_updating = False
else:
self.layers_need_updating = True
def onpbPrint_text_Clicked(self):
# Test 2 (not working)
# lyr_nm=self.mMapLayerCB.currentLayer()
# feats = [f for f in lyr_nm.getFeatures()]
# attrib_n = "FEATURETYP"
# for feat in feats:
# name = feat[attrib_n]
# print (name)
# self.pbPrint.setText(str(name))
# Test 1 (load layer from drop down and get attribute names to fill into field combo box)
lyr_nm=self.mMapLayerCB.currentLayer()
print (lyr_nm)
self.pbPrint.setText(str(lyr_nm))
for lyr in lyr_nm.fields():
attribname = lyr.name()
print (attribname)
# if attribname == "Log Reason":
# text = lyr.attribute()
# print (text)
# self.pbPrint.setText(str(text))
def load_fields(self, index=0): #Ref https://www.youtube.com/watch?v=nWKyRDxUIrI
self.mFieldCB.clear()
#prov = self.mMapLayerCB[index].dataProvider()
lyr_nm=self.mMapLayerCB.currentLayer()
print (lyr_nm)
#field_name = [field.name() for field in prov.fields()]
field_name = [field.name() for field in lyr_nm.fields()]
print (field_name)
self.mFieldCB.addItems(field_name)
def load_text_values(self):
regex_search_val = self.RegexSearch.toPlainText()
OutputText_val = self.OutputText.toPlainText()
# print (regex_search_val,OutputText_val)
The push button is just to see what output I get. Once we get the text inputs how do we use them when the Ok button is pressed?