1

I am developing a QGIS plugin in python and hit a roadblock when displaying my GUI. I am using the plugin builder framework to develop my plugin and I have trouble displaying a checkable combo box in a scrollArea in my GUI. The code with core functionality is as follows.

def run(self):
# Only create GUI ONCE in callback, so that it will only load when the plugin is started
if self.first_start == True:
    self.first_start = False
    # Sets up the pyqt user interface
    self.dlg = EarthingToolDialog()

# Fetching the active layer in the QGIS project
layer = self.iface.activeLayer()

checkable_combo = CheckableComboBox()

# Going through each field of the layer
# and adding field names as items to the 
# combo box

for j,field in enumerate(layer.fields()):    
    checkable_combo.addItem(str(field.name()))

    # Setting the checked state to True by default
    checkable_combo.setItemChecked(j, True) 

# putting the check box inside the scroll area of the GUI
self.dlg.scrollArea.setWidget(checkable_combo)
self.dlg.scrollArea.setMinimumSize(QSize(700,400))   

# show the dialog
self.dlg.show()
# Run the dialog event loop
self.dlg.exec_()    

class EarthingToolDialog(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(EarthingToolDialog, self).__init__(parent)
        self.setupUi(self)   

class CheckableComboBox(QComboBox):
def __init__(self):
    super().__init__()
    self._changed = False

    self.view().pressed.connect(self.handleItemPressed)

def setItemChecked(self, index, checked=False):
    print('checked')
    item = self.model().item(index, self.modelColumn()) # QStandardItem object
    print(type(item))

    if checked:
        item.setCheckState(Qt.CheckState.Checked)
    else:
        item.setCheckState(Qt.CheckState.Unchecked)
        
def handleItemPressed(self, index):
    print('pressed')
    item = self.model().itemFromIndex(index)

    if item.checkState() == Qt.Checked:
        item.setCheckState(Qt.Unchecked)
    else:
        item.setCheckState(Qt.Checked)
    self._changed = True
    print('set ' +  str(item.checkState()))

def hidePopup(self):
    print('hide')
    if not self._changed:
        super().hidePopup()
    self._changed = False

def itemChecked(self, index):
    print('read')
    item = self.model().item(index, self.modelColumn())
    return item.checkState() == Qt.Checked    

In summary, the run function is the main function called by the plugin when it is loaded. self.dlg is the instance of the actual pyqt python user interface. This is rendered with the help of the EarthingToolDialog class. The checkable combo box and it's functionalities are self contained in the CheckableComboBox class.

The run function executes without any error when the plugin is loaded but the checkboxes are not visible in the combobox. Just a normal combo box with a list of items (just the standard dropdown combo box) is seen on the GUI's scroll area and not the desired checkable combo box. The CheckableComboBox class was taken from https://morioh.com/p/d1e70112347c and it runs perfectly well in the demo code shown there.

I understand that this is a very specific question and it would be great if someone could figure out what the problem might be. Thanks in advance!

Ravindu
  • 11
  • 1

1 Answers1

0
  1. Within the run function, this piece of codes didn't work for me:

    self.dlg.scrollArea.setWidget(checkable_combo)
    self.dlg.scrollArea.setMinimumSize(QSize(700,400))
    

So instead, I use:

layout = QVBoxLayout()
layout.addWidget(checkable_combo)
self.dlg.setLayout(layout)
  1. I didn't use directly this class (It was generated automatically since I use Plugin Builder, so in here I commented it):

    class EarthingToolDialog(QtWidgets.QDialog, FORM_CLASS):
        def __init__(self, parent=None):
        """Constructor."""
            super(EarthingToolDialog, self).__init__(parent)
            self.setupUi(self)
    
  2. Now, in order to display checkable combo box, CheckableComboBox constructor is changed as :

    def __init__(self):
        super().__init__()
        self._changed = False
        self.view().pressed.connect(self.handleItemPressed)
        delegate = QtWidgets.QStyledItemDelegate(self.view())
        self.view().setItemDelegate(delegate)
    

The last two lines are from the answer listed here.

Codes display checkable combo box list with all items checked by default.