How do I enforce the minimum index of any one of multiple QComboBoxes within a for loop?

a 夏天 提交于 2021-01-28 09:22:16

问题


I have a QWizard that reads the column headers of a CSV file and makes the user choose what they want with each column. In the 2nd page of this wizard, I add the combo-boxes in a for loop that loops over the column names of the CSV. All combo-boxes are mandatory fields. However, another constraint is that at least one of them must be selected to choice 3 or above (c1 or c2 in my MWE), before the user can press "Next".

In addition to self.NextButton.setEnabled(False), I also tried using isComplete and completeChanged according to this example and this question, but being a beginner to PyQt and not so good at C++, I haven't been able to understand that much of the existing documentation. For now isComplete seems to be fine but the wizard isn't registering it.

Can anyone teach me how I would be able to achieve what I wanted (the text in bold)?

from PyQt5 import QtGui, QtWidgets, QtCore
import csv

class ChooseFile(QtWidgets.QWizardPage):

    def __init__(self, parent=None):
        super(ChooseFile, self).__init__(parent)

        body = QtWidgets.QVBoxLayout()

        self.filePathShow = QtWidgets.QLineEdit(self)
        self.filePathShow.setReadOnly(True)                      # not editable
        self.registerField("filePathShow*", self.filePathShow)   # mandatory
        body.addWidget(self.filePathShow)

        browseButton = QtWidgets.QPushButton('Browse...', self)
        browseButton.clicked.connect(self.browseDialog)
        browseBox = QtWidgets.QHBoxLayout()
        browseBox.addWidget(browseButton)
        body.addLayout(browseBox)

        self.setLayout(body)

    def browseDialog(self):
        filePath, _ = QtWidgets.QFileDialog.getOpenFileName(self, 'Open CSV', '/home', '(*.csv)')
        if filePath:   # only changes if valid file, stays the same if user presses cancel
            self.setField("filePathShow", filePath)

class ChooseColumns(QtWidgets.QWizardPage):

    def __init__(self, parent=None):
        super(ChooseColumns, self).__init__(parent)

        self.box = QtWidgets.QGroupBox()
        body = QtWidgets.QVBoxLayout()
        body.addWidget(self.box)   # these are where the choices (comboboxes) go
        self.setLayout(body)


    def initializePage(self):
        filePath2 = self.field("filePathShow")
        with open(str(filePath2), 'r') as f:
            reader = csv.reader(f)
            self.columns = next(reader)            
            # make a combobox for each column
            grid = QtWidgets.QGridLayout()
            self.comboBoxes = [None] * len(self.columns)
            for i, col in enumerate(self.columns):
                grid.addWidget(QtWidgets.QLabel(col), i, 0)   # printscolumn name

                self.comboBoxes[i] = QtWidgets.QComboBox()
                self.comboBoxes[i].addItem("")         # default value since is mandatory field
                self.comboBoxes[i].addItem("a")
                self.comboBoxes[i].addItem("b")
                self.comboBoxes[i].addItem("c1")
                self.comboBoxes[i].addItem("c2")

                grid.addWidget(self.comboBoxes[i], i, 1)
                self.registerField("column" + str(i) + "*", self.comboBoxes[i]) # all mandatory
                self.comboBoxes[i].currentIndexChanged.connect(self.isComplete)
                #self.connect(self.comboBoxes[i], QtCore.SIGNAL(currentIndexChanged()), 
                #            self, QtCore.SIGNAL(completeChanged()))
                self.comboBoxes[i].currentIndexChanged.connect(self.completeChanged)   # DOESN'T WORK
            self.box.setLayout(grid)

    def isComplete(self, other):   # WORKS
        self.selections = [None] * len(self.columns)
        for i in range(len(self.selections)):   # first fill the list
            self.selections[i] = self.comboBoxes[i].currentIndex()
        #print(self.selections)
        for item in self.selections:   # then evaluate the values
            if i >= 3:
                return True
        return False


class Manager(QtWidgets.QWizard):

    def __init__(self, parent=None):
        super(Manager, self).__init__(parent)

        self.resize(500, 300)

        self.addPage(ChooseFile(self))
        self.addPage(ChooseColumns(self))


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Manager()
    w.show()
    sys.exit(app.exec_())

回答1:


The isComplete signal must return a Boolean that indicates whether it can advance to the next page or terminate the process. This method should not be invoked directly but through the completeChanged signal.

This case is special since the amount of QComboBox is variable, so if the user goes back to the previous page and selects another .csv, the amount of QComboBox should be changed and registered would be a problem so in this case I will not do it but It is directly handled using isComplete.

Finally, as the objective (I suppose) is to obtain the selected values then I will use a property of the QWizard to store that information and be able to obtain it on the last page that I added for my test.

import csv

from PyQt5 import QtGui, QtWidgets, QtCore


class ChooseFile(QtWidgets.QWizardPage):
    def __init__(self, parent=None):
        super(ChooseFile, self).__init__(parent)

        body = QtWidgets.QVBoxLayout(self)

        self.filePathShow = QtWidgets.QLineEdit(self)
        self.filePathShow.setReadOnly(True)  # not editable
        self.registerField("filePathShow*", self.filePathShow)  # mandatory
        body.addWidget(self.filePathShow)

        browseButton = QtWidgets.QPushButton("Browse...", self)
        browseButton.clicked.connect(self.browseDialog)
        browseBox = QtWidgets.QHBoxLayout()
        browseBox.addWidget(browseButton)
        body.addLayout(browseBox)

    def browseDialog(self):
        filePath, _ = QtWidgets.QFileDialog.getOpenFileName(
            self, "Open CSV", "/home", "(*.csv)"
        )
        if filePath:
            self.setField("filePathShow", filePath)


class ChooseColumns(QtWidgets.QWizardPage):
    def __init__(self, parent=None):
        super(ChooseColumns, self).__init__(parent)

        self.comboboxes = []

        box = QtWidgets.QGroupBox()
        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(box)
        self.flay = QtWidgets.QFormLayout()
        box.setLayout(self.flay)

    def initializePage(self):
        for combo in self.comboboxes:
            self.flay.removeRow(combo)
        self.comboboxes = []
        self.wizard().setProperty("indexes_selected", [])
        self.wizard().setProperty("options_selected", [])

        filePath2 = self.field("filePathShow")
        options = ("", "a", "b", "c1", "c2")
        with open(filePath2, "r") as f:
            reader = csv.reader(f)
            header = next(reader)
            for i, text in enumerate(header):
                combo = QtWidgets.QComboBox()
                combo.addItems(options)
                combo.currentIndexChanged.connect(self.completeChanged)
                self.flay.addRow(text, combo)
                self.comboboxes.append(combo)

    def isComplete(self):
        indexes = [combo.currentIndex() for combo in self.comboboxes]
        is_completed = all(index >= 1 for index in indexes) and any(
            index >= 3 for index in indexes
        )
        self.wizard().setProperty("indexes_selected", indexes)
        self.wizard().setProperty(
            "options_selected", [combo.currentText() for combo in self.comboboxes]
        )
        return is_completed


class FinalPage(QtWidgets.QWizardPage):
    def initializePage(self):
        print(self.wizard().property("indexes_selected"))
        print(self.wizard().property("options_selected"))


class Manager(QtWidgets.QWizard):
    def __init__(self, parent=None):
        super(Manager, self).__init__(parent)

        self.resize(500, 300)

        self.addPage(ChooseFile())
        self.addPage(ChooseColumns())
        self.addPage(FinalPage())


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Manager()
    w.show()
    sys.exit(app.exec_())


来源:https://stackoverflow.com/questions/60607172/how-do-i-enforce-the-minimum-index-of-any-one-of-multiple-qcomboboxes-within-a-f

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!