如何在 for 循环中强制执行多个 QComboBox 中任何一个的最小索引? [英] How do I enforce the minimum index of any one of multiple QComboBoxes within a for loop?

查看:57
本文介绍了如何在 for 循环中强制执行多个 QComboBox 中任何一个的最小索引?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 QWizard,它可以读取 CSV 文件的列标题并让用户选择他们想要的每一列.在此向导的第二页中,我将组合框添加到循环 CSV 的列名的 for 循环中.所有组合框都是必填字段.但是,另一个限制是必须至少选择其中一个来选择 3 或以上(在我的 MWE 中为 c1 或 c2),然后用户才能按下一步".

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".

除了self.NextButton.setEnabled(False),我还尝试使用isCompletecompleteChanged 根据this 示例和 this 问题,但作为 PyQt 的初学者并且不太擅长 C++,我没有'无法理解现有文档的大部分内容.现在 isComplete 似乎没问题,但向导没有注册它.

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_())

推荐答案

isComplete 信号必须返回一个布尔值,指示它是否可以前进到下一页或终止进程.此方法不应直接调用,而应通过 completeChanged 信号调用.

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.

这种情况比较特殊,因为QComboBox的数量是可变的,所以如果用户返回上一页并选择另一个.csv,QComboBox的数量应该改变并注册将是一个问题,所以在这种情况下我会不做但是直接用isComplete处理.

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.

最后,由于目标(我想)是获取选定的值,所以我将使用 QWizard 的一个属性来存储该信息,并能够在我为测试添加的最后一页上获取它.

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_())

这篇关于如何在 for 循环中强制执行多个 QComboBox 中任何一个的最小索引?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆