pythonpyqtqt5pyqt5qspinbox

Loop through QSpinbox when reaches the end


Is there any way to create a QSpinbox that sets itself to the first value, when it reaches the end, and the step up button is pressed again?

I tried doing it in a custom QSpinBox but what happens is that when it reaches to the last value, y gets instantly reset, which leads to never seeing the last value.

from PyQt5.QtWidgets import QSpinBox
from music import TonoFactory

_tf = TonoFactory()


class StringBox(QSpinBox):
    def __init__(self, parent=None):
        super(StringBox, self).__init__(parent)
        strings = []
        for key in _tf.notas.keys():
            strings.append(key)
        self.setStrings(strings)
        self.editingFinished.connect(self.reset_spin)

    def strings(self):
        return self._strings

    def setStrings(self, strings):
        strings = list(strings)
        self._strings = tuple(strings)
        self._values = dict(zip(strings, range(len(strings))))
        self.setRange(0, len(strings) - 1)

    def textFromValue(self, value):
        return self._strings[value]

    def valueFromText(self, text):
        return self._values[text]

    def reset_spin(self):
        if self.value() == len(self.strings()) -1:
            self.setValue(0)

Solution

  • A solution strategy is to add an element before and to the last so that the buttons remain enabled, we intercept the changes so that instead of going to the last go to the second, and vice versa, instead of going to the first one, you must go to the last one.

    Example:

    class StringBox(QSpinBox):
        def __init__(self, parent=None):
            super(StringBox, self).__init__(parent)
            strings = []
            texts = ["do", "re", "mi", "fa", "sol", "la", "si"]
            for key in texts:
                strings.append(key)
            self.setStrings([""] + strings + ["-"])
            self.setValue(1)
    
        def strings(self):
            return self._strings
    
        def setStrings(self, strings):
            strings = list(strings)
            self._strings = tuple(strings)
            self._values = dict(zip(strings, range(len(strings))))
            self.setRange(0, len(strings)-1)
    
        def textFromValue(self, value):
            return self._strings[value]
    
        def valueFromText(self, text):
            return self._values[text]
    
        def stepBy(self, step):
            if self.value() == 1 and step == -1:
                self.setValue(self.maximum())
            elif self.value() == self.maximum() -1  and step == 1:
                self.setValue(0)
            QSpinBox.stepBy(self, step)
    
    
    if __name__ == "__main__":
        import sys
        app = QApplication(sys.argv)
        w = StringBox()
        w.show()
        sys.exit(app.exec_())
    

    Note: Since you are using a dictionary and these can not have repeated keys, I recommend that the elements you add be different from the texts you show.