ComboBox function currentIndexChanged not working

2020-02-07 04:59发布

I have taken two comboBoxes i.e., comboBox1 and comboBox_2 and two functions test and test1 and calling them using currentIndexChanged (self.comboBOx1.currentIndexChanged and self.comboBOx_2.currentIndexChanged). When a value is selected from comboBox1 its corresponding function(self.comboBOx1.currentIndexChanged) is called and same for comboBox_2. On selection of value from comboBox1 changes the values in comboBox_2 and its working fine. But the problem I have got here is that at first when I select a value from comboBox1 and comboBox_2 I'm getting the expected values from the called function(printing 'hello'). The second time when I select a value from comboBox1 only test function should be called but here both the functions(test and test1) are getting called and the second function (test1) is getting called twice(printing 'hello' twice) and for third time its getting called four times(printing 'hello' four times). Please can anyone help me with this problem.?

Code:

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(800, 600)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.comboBox1 = QtGui.QComboBox(self.centralwidget)
        self.comboBox1.setGeometry(QtCore.QRect(310, 150, 171, 31))
        self.comboBox1.setObjectName(_fromUtf8("comboBox1"))
        self.comboBox1.addItem(_fromUtf8(""))
        self.comboBox1.addItem(_fromUtf8(""))
        self.comboBox1.addItem(_fromUtf8(""))
        self.comboBox1.addItem(_fromUtf8(""))
        self.comboBox_2 = QtGui.QComboBox(self.centralwidget)
        self.comboBox_2.setGeometry(QtCore.QRect(310, 240, 171, 41))
        self.comboBox_2.setObjectName(_fromUtf8("comboBox_2"))
        self.comboBox_2.addItem(_fromUtf8(""))
        self.comboBox_2.addItem(_fromUtf8(""))
        self.comboBox_2.addItem(_fromUtf8(""))
        self.comboBox_2.addItem(_fromUtf8(""))
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
        self.comboBox1.setItemText(0, _translate("MainWindow", "select", None))
        self.comboBox1.setItemText(1, _translate("MainWindow", "a", None))
        self.comboBox1.setItemText(2, _translate("MainWindow", "b", None))
        self.comboBox1.setItemText(3, _translate("MainWindow", "c", None))
        self.comboBox_2.setItemText(0, _translate("MainWindow", "select", None))
        self.comboBox_2.setItemText(1, _translate("MainWindow", "p", None))
        self.comboBox_2.setItemText(2, _translate("MainWindow", "q", None))
        self.comboBox_2.setItemText(3, _translate("MainWindow", "r", None))
        self.comboBox_2.setEnabled(0)
        self.comboBox1.currentIndexChanged.connect(self.test)

    def test(self):
        s = str(self.comboBox1.currentText())
        res=['aa','bb','cc','dd']

        if (s == "- - select - -"):
            self.comboBox_2.setEnabled(0)
            self.comboBox_2.setCurrentIndex(0)
        elif(len(s)== 0):
            self.comboBox_2.setEnabled(1)
            self.comboBox_2.clear()
            self.comboBox_2.addItem("- - select - -")
            self.comboBox_2.addItem("New Checklist")
        else:
            self.comboBox_2.setEnabled(1)
            self.comboBox_2.clear()
            self.comboBox_2.addItem("- - select - -")
            self.comboBox_2.addItem("New Checklist")
            self.comboBox_2.addItems(res)
            self.comboBox_2.currentIndexChanged.connect(self.test1)

    def test1(self):
        print ("Hello")

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

1条回答
放荡不羁爱自由
2楼-- · 2020-02-07 05:30

To understand the behavior we will use the following examples:

Example 1:

from PyQt4 import QtCore, QtGui


def on_clicked():
    print("clicked")


if __name__ == "__main__":
    import sys

    app = QtGui.QApplication(sys.argv)
    button = QtGui.QPushButton("Press me")
    for _ in range(4):
        button.clicked.connect(on_clicked)
    button.show()
    sys.exit(app.exec_())

When you press the button it prints 4 times because Qt does not remember if there was already a connection between signal and a function previously, so if there are n connections between the same signal and function they will be invoked n times when the signal is emitted.

Example 2:

from PyQt4 import QtCore, QtGui


def on_currentIndexChanged(ix):
    print("currentIndex:", ix)


if __name__ == "__main__":
    import sys

    app = QtGui.QApplication(sys.argv)
    combo = QtGui.QComboBox()
    print("currentIndex:", combo.currentIndex())
    combo.currentIndexChanged.connect(on_currentIndexChanged)
    button_add = QtGui.QPushButton("Add Items")
    button_add.clicked.connect(lambda: combo.addItems("1 2 3".split()))
    button_clear = QtGui.QPushButton("Clear")
    button_clear.clicked.connect(combo.clear)
    w = QtGui.QWidget()
    lay = QtGui.QVBoxLayout(w)
    for widget in (combo, button_add, button_clear):
        lay.addWidget(widget)
    w.show()
    sys.exit(app.exec_())

The default currentIndex of the QComboBox is -1, when you add items this changes to the currentIndex of 0, and when you clean the QComboBox the currentIndex reverts to -1. So when you add or clean the items, the currentIndexChanged signal is emitted.


Based on the above, I will explain the behavior that you point out: When a new currentIndex is selected in the QCombobox 1 the test method is invoked and if it enters the else statement after cleaning and adding the items you make the first connection, if the same thing is repeated now as there is a connection, the currentIndexChanged signal is emitted twice (one for clear() and another for addItems()) and you also create a second connection, if it is repeated again, the signal is emitted 4 times (1 clear() x 2 connections + 1 addItems() x 2 connections).

Solution:

  • Make the connection in a function that is invoked only once.
  • So that the clear() signal and addItems() do not emit the currentIndexChanged signal you must use blockSignals().
  • As an additional point it is recommended not to modify the code generated by Qt Designer, it is advisable to create another class that uses the initial class as an interface, in addition to using the decoration @QtCore.pyqtSlot().
from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(800, 600)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.comboBox1 = QtGui.QComboBox(self.centralwidget)
        self.comboBox1.setGeometry(QtCore.QRect(310, 150, 171, 31))
        self.comboBox1.setObjectName(_fromUtf8("comboBox1"))
        self.comboBox1.addItem(_fromUtf8(""))
        self.comboBox1.addItem(_fromUtf8(""))
        self.comboBox1.addItem(_fromUtf8(""))
        self.comboBox1.addItem(_fromUtf8(""))
        self.comboBox_2 = QtGui.QComboBox(self.centralwidget)
        self.comboBox_2.setGeometry(QtCore.QRect(310, 240, 171, 41))
        self.comboBox_2.setObjectName(_fromUtf8("comboBox_2"))
        self.comboBox_2.addItem(_fromUtf8(""))
        self.comboBox_2.addItem(_fromUtf8(""))
        self.comboBox_2.addItem(_fromUtf8(""))
        self.comboBox_2.addItem(_fromUtf8(""))
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
        self.comboBox1.setItemText(0, _translate("MainWindow", "select", None))
        self.comboBox1.setItemText(1, _translate("MainWindow", "a", None))
        self.comboBox1.setItemText(2, _translate("MainWindow", "b", None))
        self.comboBox1.setItemText(3, _translate("MainWindow", "c", None))
        self.comboBox_2.setItemText(0, _translate("MainWindow", "select", None))
        self.comboBox_2.setItemText(1, _translate("MainWindow", "p", None))
        self.comboBox_2.setItemText(2, _translate("MainWindow", "q", None))
        self.comboBox_2.setItemText(3, _translate("MainWindow", "r", None))


class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)

        self.comboBox_2.setEnabled(False)
        self.comboBox1.currentIndexChanged[str].connect(self.test)
        self.comboBox_2.currentIndexChanged.connect(self.test1)

    @QtCore.pyqtSlot(str)
    def test(self, s):
        res=['aa','bb','cc','dd']

        if s == "- - select - -":
            self.comboBox_2.setEnabled(False)
            self.comboBox_2.setCurrentIndex(0)
        elif not s:
            self.comboBox_2.setEnabled(True)
            self.comboBox_2.blockSignals(True)
            self.comboBox_2.clear()
            self.comboBox_2.addItem("- - select - -")
            self.comboBox_2.addItem("New Checklist")
            self.comboBox_2.blockSignals(False)
        else:
            self.comboBox_2.setEnabled(True)
            self.comboBox_2.blockSignals(True)
            self.comboBox_2.clear()
            self.comboBox_2.addItem("- - select - -")
            self.comboBox_2.addItem("New Checklist")
            self.comboBox_2.addItems(res)
            self.comboBox_2.blockSignals(False)


    @QtCore.pyqtSlot(int)
    def test1(self, ix):
        print("Hello", ix)

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())
查看更多
登录 后发表回答