pythonqtqtreeviewqitemdelegate

Is there a way to put negative floats in a QSpinBox?


I am trying to find a way to put negative numbers in a QDoubleSpinBox. I read the documentation but haven't found the solution yet. Here is the class I made to customize my QDoubleSpinBox :

class ComboBoxDelegate(QStyledItemDelegate):
    """A delegate that allows the user to change integer values from the model
       using a spin box widget. """

    def __init__(self, parent=None):
        super().__init__(parent)

    def createEditor(self, parent, option, index : QModelIndex):
        if index.column() == 0 :
            editor = QLineEdit(parent)
            return editor
        

        if index.column() == 1 :
            combo = QComboBox(parent)
            combo.addItems(["len","diam","conc"])
            editor = combo
            
            return editor
        
        if index.column() > 1 :
            editor = CustomDoubleSpinbox(parent)
            editor.setDecimals(3)
            return editor

    def setEditorData(self, editor , index):
        value = index.model().data(index, Qt.EditRole)
        if type(editor) == QComboBox :
            editor.setCurrentText(str(value))

        if type(editor) == CustomDoubleSpinbox :
            editor.setValue(value)

        if type(editor) == QLineEdit :
            editor.setText(value)

    def setModelData(self, editor , model, index : QModelIndex):
        if type(editor) == QComboBox :
            value = editor.currentText()
        if type(editor) == CustomDoubleSpinbox :
            editor.interpretText()
            value = editor.value()
        if type(editor) == QLineEdit :
            value = editor.text()
        model.setData(index, value, Qt.EditRole)

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)





class CustomDoubleSpinbox(QDoubleSpinBox):
    def validate(self, text: str, pos: int) -> object:
        text = text.replace(".", ",")
        return QDoubleSpinBox.validate(self, text, pos)

    def valueFromText(self, text: str) -> float:
        text = text.replace(",", ".")
        return float(text)

EDIT h4z3 found the solution in the documentation : QDoubleSpinBox for python. By setting a negative minimum with the setMinimum method, it works.


Solution

  • As docs say:

    Constructs a spin box with 0.0 as minimum value and 99.99 as maximum value, a step value of 1.0 and a precision of 2 decimal places.

    But just below there's:

    See also setMinimum() setMaximum() setSingleStep()

    The linked setMinimum docs

    So since you're inheriting from QDoubleSpinBox, it would be the best to modify this in init:

    class CustomDoubleSpinbox(QDoubleSpinBox):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)  # to not break inheritance
            self.setMinimum(-99.99)  # we inherited the method, so we can now set our own minimum to be used
    
        def validate(self, text: str, pos: int) -> object:
            text = text.replace(".", ",")
            return QDoubleSpinBox.validate(self, text, pos)
    
        def valueFromText(self, text: str) -> float:
            text = text.replace(",", ".")
            return float(text)
    

    This way, every time you create the object of CustomDoubleSpinbox class, the minimum will be always changed - as opposed to using setMinimum somewhere else in the code.

    The *args and **kwargs are a way to ensure the code doesn't break if signature changes. In this case, QDoubleSpinBox only takes optional parent and we could just hardcode it. But I like pretty and flexible code. (You can switch those two lines to def __init__(self, parent=None): and super().__init__(parent) - it will be the same. Just remember that setting min needs to be after the super, not before.)

    You could also use setRange to be explicit about both min and max (because max is now not obvious without reading docs).

    I also used -99.99 in setMinimum to match default max of 99.99 - but of course you might want to adjust that value as well.