2

I have a spinbox in PyQt5 like below. How can I make the selection reversed? i.e. If I click down arrow, the value goes up, vice versa.

spinbox

3 Answers 3

2

A possible solution is to override the stepBy() and stepEnabled() methods:

import sys
from PyQt5 import QtWidgets


class ReverseSpinBox(QtWidgets.QSpinBox):
    def stepEnabled(self):
        if self.wrapping() or self.isReadOnly():
            return super().stepEnabled()
        ret = QtWidgets.QAbstractSpinBox.StepNone
        if self.value() > self.minimum():
            ret |= QtWidgets.QAbstractSpinBox.StepUpEnabled
        if self.value() < self.maximum():
            ret |= QtWidgets.QAbstractSpinBox.StepDownEnabled
        return ret

    def stepBy(self, steps):
        return super().stepBy(-steps)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    w = ReverseSpinBox()
    w.resize(320, 20)
    w.show()
    sys.exit(app.exec_())
Sign up to request clarification or add additional context in comments.

Comments

0

A fully working app:

# ReverseSpinbox.py    2022-10-25 4:43:56 PM
# 
# Based on 'How to reverse spinbox selection in PyQt5?'
# https://stackoverflow.com/questions/62821244/how-to-reverse-spinbox-selection-in-pyqt5
# 'A possible [ed: now verified] solution is to override the stepBy() and stepEnabled() methods:'
# 
# Also based on 'PyQt5 - Creating String Spin Box'
# https://www.geeksforgeeks.org/pyqt5-creating-string-spin-box/

import sys
from PyQt5.QtWidgets import * 
from PyQt5 import QtCore, QtGui
from PyQt5.QtGui import * 
from PyQt5.QtCore import * 

class MyAppWindow( QMainWindow ) :
    
    def __init__( self ) :
        super().__init__()
    
        self.setWindowTitle( 'Creating Reverse String Spin Box ' )
        self.setWindowIcon( QIcon( 'Python_and_Qt.PNG' ) )
        self.resize( 600, 400 )
        self.move( QApplication.desktop().screen().rect().center() - self.rect().center() )
        
        self.UiComponents()
        self.show()
    
    def UiComponents( self ) :
    
        #string_pin_box = StringBox( self )
        string_revSpinBox = ReverseSpinBox( self )
        
        string_revSpinBox.setGeometry( 100, 100, 200, 40 )
    
#end MyAppWindow class

class ReverseSpinBox( QSpinBox ) :
    
    def __init__( self, parent = None ) :
        super( QSpinBox, self ).__init__( parent )
    
        strings = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G' ]
    
        # Make the spinbox items strings.
        self.SetStrings( strings )
    
    # Define method SetStrings similarly to the setValue method.
    def SetStrings( self, strings ) :
    
        #strings = list( strings )   # 'strings' is already a list.
    
        self.strings_tuple = tuple( strings )
        
        # A QSpinBox/ReverseSpinBox's items' indices.
        self.setRange( 0, len( strings )-1 )
    
    # Overide the QSpinBox 'textFromValue' method.
    # Maps 'strings' integer indices to its string values.
    def textFromValue( self, int_index ) :
    
        # Returning a string associated to the dictionary's item key value.
        return self.strings_tuple[ int_index ]
    
    # Overide the QSpinBox 'stepEnabled' method.
    def stepEnabled( self ) :
        
        if self.wrapping() or self.isReadOnly() :
            return super().StepEnabled()
        
        spinbox_operation_flags = QAbstractSpinBox.StepNone
        
        # Set according to whether the up or down button has been pushed (?)
        if self.value() >= self.minimum() :
            spinbox_operation_flags |= QAbstractSpinBox.StepUpEnabled
        
        if self.value() <= self.maximum() :
            spinbox_operation_flags |= QAbstractSpinBox.StepDownEnabled
        
        return spinbox_operation_flags
    
    # Overide the QSpinBox 'stepEnabled' method.
    # Reverse the operation of the up and down buttons.
    def stepBy( self, steps ) :
        return super().stepBy( -steps )

#end ReverseSpinBox class

if __name__ == "__main__" :
    
    App = QApplication( sys.argv )
    window = MyAppWindow()
    sys.exit( App.exec() )

Comments

0

Based on @eyllanesc answer, but ported to PyQt6 (also works on PyQt5).

Create your own class that overrides the original QSpinBox. Override the stepBy() and stepEnabled() methods:

import sys
from PyQt6 import QtWidgets


class ReverseSpinBox(QtWidgets.QSpinBox):
    def stepEnabled(self):
        if self.wrapping() or self.isReadOnly():
            return super().stepEnabled()
        ret = QtWidgets.QAbstractSpinBox.StepEnabledFlag.StepNone
        if self.value() > self.minimum():
            ret |= QtWidgets.QAbstractSpinBox.StepEnabledFlag.StepUpEnabled
        if self.value() < self.maximum():
            ret |= QtWidgets.QAbstractSpinBox.StepEnabledFlag.StepDownEnabled
        return ret

    def stepBy(self, steps):
        return super().stepBy(-steps)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    w = ReverseSpinBox()
    w.resize(320, 20)
    w.show()
    sys.exit(app.exec())

It differs from the @eyllanesc code by fully qualified enums, and removing underscore in app.exec().

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.