pythoncheckboxpyqtqgispyqgis

CheckableComboBox in PyQGIS (waiting for choice)


I am using this code in QGIS's built-in python-editor. How can I make the script wait while I mark the necessary lines, and only then continue execution? So far, I cannot do this: the window starts, but the script continues to execute and therefore there is no way to use the select list. For example, can I somehow add the "Ok" button there (as in a standard dialog box)?

script 1 in QGS's build-in python-editor script 2 in QGS's build-in python-editor

from qgis.PyQt import *
from qgis.core import *

class CheckableComboBox(QComboBox):

# Subclass Delegate to increase item height
class Delegate(QStyledItemDelegate):
    def sizeHint(self, option, index):
        size = super().sizeHint(option, index)
        size.setHeight(20)
        return size

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

    # Make the combo editable to set a custom text, but readonly
    self.setEditable(True)
    self.lineEdit().setReadOnly(True)
    # Make the lineedit the same color as QPushButton
    palette = qApp.palette()
    palette.setBrush(QPalette.Base, palette.button())
    self.lineEdit().setPalette(palette)

    # Use custom delegate
    self.setItemDelegate(CheckableComboBox.Delegate())

    # Update the text when an item is toggled
    self.model().dataChanged.connect(self.updateText)

    # Hide and show popup when clicking the line edit
    self.lineEdit().installEventFilter(self)
    self.closeOnLineEditClick = False

    # Prevent popup from closing when clicking on an item
    self.view().viewport().installEventFilter(self)

def resizeEvent(self, event):
    # Recompute text to elide as needed
    self.updateText()
    super().resizeEvent(event)

def eventFilter(self, object, event):

    if object == self.lineEdit():
        if event.type() == QEvent.MouseButtonRelease:
            if self.closeOnLineEditClick:
                self.hidePopup()
            else:
                self.showPopup()
            return True
        return False

    if object == self.view().viewport():
        if event.type() == QEvent.MouseButtonRelease:
            index = self.view().indexAt(event.pos())
            item = self.model().item(index.row())

            if item.checkState() == Qt.Checked:
                item.setCheckState(Qt.Unchecked)
            else:
                item.setCheckState(Qt.Checked)
            return True
    return False

def showPopup(self):
    super().showPopup()
    # When the popup is displayed, a click on the lineedit should close it
    self.closeOnLineEditClick = True

def hidePopup(self):
    super().hidePopup()
    # Used to prevent immediate reopening when clicking on the lineEdit
    self.startTimer(100)
    # Refresh the display text when closing
    self.updateText()

def timerEvent(self, event):
    # After timeout, kill timer, and reenable click on line edit
    self.killTimer(event.timerId())
    self.closeOnLineEditClick = False

def updateText(self):
    texts = []
    for i in range(self.model().rowCount()):
        if self.model().item(i).checkState() == Qt.Checked:
            texts.append(self.model().item(i).text())
    text = ", ".join(texts)

    # Compute elided text (with "...")
    metrics = QFontMetrics(self.lineEdit().font())
    elidedText = metrics.elidedText(text, Qt.ElideRight, self.lineEdit().width())
    self.lineEdit().setText(elidedText)

def addItem(self, text, data=None):
    item = QStandardItem()
    item.setText(text)
    if data is None:
        item.setData(text)
    else:
        item.setData(data)
    item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable)
    item.setData(Qt.Unchecked, Qt.CheckStateRole)
    self.model().appendRow(item)

def addItems(self, texts, datalist=None):
    for i, text in enumerate(texts):
        try:
            data = datalist[i]
        except (TypeError, IndexError):
            data = None
        self.addItem(text, data)

def currentData(self):
    # Return the list of selected items data
    res = []
    for i in range(self.model().rowCount()):
        if self.model().item(i).checkState() == Qt.Checked:
            res.append(self.model().item(i).data())
    return res 


print("Starting...")
comunes = ['Ameglia', 'Arcola', 'Bagnone', 'Bolano', 'Carrara', 'Casola', 'Barnaul', 'London']

combo = CheckableComboBox()
combo.resize(350,300)
combo.setWindowTitle('CheckableComboBox')
combo.setWindowFlags(Qt.WindowStaysOnTopHint)
combo.show()
combo.addItems(comunes)
    
print(combo.currentData())

Solution

  • The problem solved by adding checkable_combobox to the QDialog. Here is the code using QgsCheckableComboBox(): https://gis.stackexchange.com/questions/376901/how-to-put-qgscheckablecombobox-into-standby

    from qgis.PyQt import QtGui
    from qgis.core import *
    planet_list = ["Venus", "Earth", "Mars", "Jupiter", "Pluto"]
    items = QgsCheckableComboBox()
    items.addItems(planet_list)
    dlg = QDialog()
    layout = QVBoxLayout()
    layout.addWidget(items)
    dlg.setLayout(layout)
    dlg.exec_()
    print('\n\n-----------CheckedItems: ', items.checkedItems())