如何使用 QDoubleSpinBoxes 更改 QDoubleSpinBoxes 中的值?

How to change values in QDoubleSpinBoxes using with QDoubleSpinBoxes?

下面是我的例子和我的代码尝试:

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(QtWidgets.QMainWindow):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(469, 348)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout_3 = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout_3.setObjectName("gridLayout_3")
        self.frame = QtWidgets.QFrame(self.centralwidget)
        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame.setObjectName("frame")
        self.gridLayout_2 = QtWidgets.QGridLayout(self.frame)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.total_spin = QtWidgets.QDoubleSpinBox(self.frame)
        self.total_spin.setObjectName("total_spin")
        self.gridLayout_2.addWidget(self.total_spin, 0, 1, 1, 1)
        self.totalLabel = QtWidgets.QLabel(self.frame)
        self.totalLabel.setObjectName("totalLabel")
        self.gridLayout_2.addWidget(self.totalLabel, 0, 0, 1, 1)
        self.gridLayout = QtWidgets.QGridLayout()
        self.gridLayout.setObjectName("gridLayout")
        self.SpinBox_two = QtWidgets.QDoubleSpinBox(self.frame)
        self.SpinBox_two.setObjectName("SpinBox_two")
        self.gridLayout.addWidget(self.SpinBox_two, 1, 0, 1, 1)
        self.two_amount = QtWidgets.QDoubleSpinBox(self.frame)
        self.two_amount.setObjectName("two_amount")
        self.gridLayout.addWidget(self.two_amount, 1, 1, 1, 1)
        self.five_amount = QtWidgets.QDoubleSpinBox(self.frame)
        self.five_amount.setObjectName("five_amount")
        self.gridLayout.addWidget(self.five_amount, 4, 1, 1, 1)
        self.SpinBox_one = QtWidgets.QDoubleSpinBox(self.frame)
        self.SpinBox_one.setObjectName("SpinBox_one")
        self.gridLayout.addWidget(self.SpinBox_one, 0, 0, 1, 1)
        self.three_amount = QtWidgets.QDoubleSpinBox(self.frame)
        self.three_amount.setObjectName("three_amount")
        self.gridLayout.addWidget(self.three_amount, 2, 1, 1, 1)
        self.one_amount = QtWidgets.QDoubleSpinBox(self.frame)
        self.one_amount.setObjectName("one_amount")
        self.gridLayout.addWidget(self.one_amount, 0, 1, 1, 1)
        self.SpinBox_three = QtWidgets.QDoubleSpinBox(self.frame)
        self.SpinBox_three.setObjectName("SpinBox_three")
        self.gridLayout.addWidget(self.SpinBox_three, 2, 0, 1, 1)
        self.SpinBox_four = QtWidgets.QDoubleSpinBox(self.frame)
        self.SpinBox_four.setObjectName("SpinBox_four")
        self.gridLayout.addWidget(self.SpinBox_four, 3, 0, 1, 1)
        self.four_amount = QtWidgets.QDoubleSpinBox(self.frame)
        self.four_amount.setObjectName("four_amount")
        self.gridLayout.addWidget(self.four_amount, 3, 1, 1, 1)
        self.SpinBox_five = QtWidgets.QDoubleSpinBox(self.frame)
        self.SpinBox_five.setObjectName("SpinBox_five")
        self.gridLayout.addWidget(self.SpinBox_five, 4, 0, 1, 1)
        self.gridLayout_2.addLayout(self.gridLayout, 1, 0, 1, 2)
        self.gridLayout_3.addWidget(self.frame, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 469, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        ####
        self.one_amount.setReadOnly(True)
        self.two_amount.setReadOnly(True)
        self.three_amount.setReadOnly(True)
        self.four_amount.setReadOnly(True)
        self.five_amount.setReadOnly(True)
        
        self.total_spin.setMaximum(99999999.99)
        self.one_amount.setMaximum(99999999.99)
        self.two_amount.setMaximum(99999999.99)
        self.three_amount.setMaximum(99999999.99)
        self.four_amount.setMaximum(99999999.99)
        self.five_amount.setMaximum(99999999.99)
        
        self.SpinBox_one.setMaximum(100.00)
        self.boxes = [self.SpinBox_one, self.SpinBox_two, self.SpinBox_three, self.SpinBox_four, self.SpinBox_five]

        self.SpinBox_one.valueChanged.connect(self.limit)
        self.SpinBox_two.valueChanged.connect(self.limit)
        self.SpinBox_three.valueChanged.connect(self.limit)
        self.SpinBox_four.valueChanged.connect(self.limit)
        ####
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.totalLabel.setText(_translate("MainWindow", "total"))
        ###
    def limit(self, value):
        i = self.boxes.index(self.sender())
        total = value + sum(box.value() for box in self.boxes[:i])
        for box in self.boxes[i + 1:]:
            box.blockSignals(True) # Avoid extra calls to limit()
            box.setMaximum(100 - total)
            box.blockSignals(False)
            total += box.value()

        if self.SpinBox_one.valueChanged:
            self.one_amount.setValue(self.total_spin.value() / 100 * self.SpinBox_one.value())
        if self.SpinBox_two.valueChanged:
            self.two_amount.setValue(self.total_spin.value() / 100 * self.SpinBox_two.value())
        if self.SpinBox_three.valueChanged:
            self.three_amount.setValue(self.total_spin.value() / 100 * self.SpinBox_three.value())
        if self.SpinBox_four.valueChanged:
            self.four_amount.setValue(self.total_spin.value() / 100 * self.SpinBox_four.value())
        if self.SpinBox_five.valueChanged:
            self.five_amount.setValue(self.total_spin.value() / 100 * self.SpinBox_five.value())
        ###
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

它有 total_spin 手动设置值的框,5 个名为 self.SpinBox_one, self.SpinBox_two, self.SpinBox_three, self.SpinBox_four, self.SpinBox_five 的 QDoubleSpinBoxes 将使用以下代码手动设置值,限制为 100%:

    def limit(self, value):
        i = self.boxes.index(self.sender())
        total = value + sum(box.value() for box in self.boxes[:i])
        for box in self.boxes[i + 1:]:
            box.blockSignals(True) # Avoid extra calls to limit()
            box.setMaximum(100 - total)
            box.blockSignals(False)
            total += box.value()

和另外5个名为self.one_amount, self.SpinBox_three, self.SpinBox_four, self.SpinBox_five的QDoubleSpinBoxes将在self.SpinBox_one, self.SpinBox_two, self.SpinBox_three, self.SpinBox_four, self.SpinBox_five值更改时自动设置值。例如:如果 self.SpinBox_one 值更改,将执行 self.total_spin.value() / 100 * self.SpinBox_one.value() 并将计算值设置为 self.one_amount。而剩下的也在发生link这个。 但是最后一个(self.SpinBox_five)不起作用。如果 self.SpinBox_five.valueChanged 值改变了它不计算也不设置值。 self.five_amount.setValue(self.total_spin.value() / 100 * self.SpinBox_five.value())。如何解决上述问题和第二个问题是:它不应该覆盖百分比值:例如:如果我将 5 self.SpinBox_one, self.SpinBox_two, self.SpinBox_three, self.SpinBox_four, self.SpinBox_five 值(百分比)设置为 50, 20, 10, 10, 10 并且如果我将第一个值从 50 更改到 60,它会将最后一个框 10 更改为 0。在这种情况下,如果 100% 打包,则在每个 QDoubleSpinBoxes 中都不应更改。如果值(百分比)为 50, 20, 10, 10 并且最后一个为空。在这种情况下,上述 self.SpinBox_one, self.SpinBox_two, self.SpinBox_three, self.SpinBox_four 之一可以添加剩余的 10%。之后应该打包。如何做到这一点。

如果我没理解错的话,您希望所有旋转框在总值为 100 时锁定,并且不允许旋转框覆盖其下方的值.在这种情况下,limit 函数将更易于实现,但因此当总值达到 100 时,需要先减少其中一个旋转框,然后才能增加其中任何一个。

此外,这些语句 - if self.SpinBox_one.valueChanged: - 不会比较旋转框是否发出信号(使用 QObject.sender() 来做到这一点)。 valueChanged 属性 指向该对象的 pyqtBoundSignal 并且将始终评估为 True 只是因为它存在。现在更好的结构是将旋转框放在字典中。

self.boxes = {self.SpinBox_one: self.one_amount,
              self.SpinBox_two: self.two_amount,
              self.SpinBox_three: self.three_amount,
              self.SpinBox_four: self.four_amount,
              self.SpinBox_five: self.five_amount}

对于每个框,将其最大值设置为其当前值 + 100 中的剩余金额。并且可以分配与发件人对应的旋转框的值,无需任何比较。

def limit(self, value):
    remainder = 100 - sum(box.value() for box in self.boxes)
    for box in self.boxes:
        box.setMaximum(box.value() + remainder)

    self.boxes[self.sender()].setValue(self.total_spin.value() / 100 * value)

如评论中所述,只是提醒连接 SpinBox_five。

self.SpinBox_five.valueChanged.connect(self.limit)