BenB
BenB

Reputation: 1050

How to prevent a QDoubleSpinBox from changing values

I've written a GUI for a script that does some geometrical calculations. Certain ranges of values break the computation (e.g. find the intersection of two shapes that don't intersect.) I raise exceptions in those cases. I'd like to prevent the user from adjusting the spinbox value beyond the point where exceptions are raised.

I've tried overwriting the validator method for the QDoubleSpinBox. This works great when I manually enter values with the keyboard. But, it doesn't prevent me from clicking the up and down arrows.

How I can limit the ability of the user to run-up the values outside of the acceptable range?

Note: The actual some_complicated_function involves the values from 5 different spinboxes.

from PyQt4 import QtCore, QtGui
import sys

def some_complicated_function(val_a):
    if val_a + 3 < 10:
        return True
    else:
        raise Exception("Giant number!")

class SpinBoxSpecial(QtGui.QDoubleSpinBox):
    def validate(self, value, pos):
#         print float(value)
        try:
            some_complicated_function(float(value))
            print "yup"
            return QtGui.QValidator.Acceptable, QtGui.QValidator.Acceptable
        except:
            print "nope"
            return QtGui.QValidator.Invalid, QtGui.QValidator.Invalid

a = QtGui.QApplication(sys.argv)       
w = QtGui.QMainWindow()
w.resize(320, 100)
w.setWindowTitle("PyQT Python Widget!") 

spinbox = SpinBoxSpecial(w)
spinbox.move(20, 20)
spinbox.CorrectionMode = QtGui.QAbstractSpinBox.CorrectToPreviousValue

w.show() 

sys.exit(a.exec_())

Edit: The basic ask is: I want to call a function when the value of a spinbox changes (via mouse or keyboard). If that function throws an exception, I want the value of the spinbox to revert to what it was.

Upvotes: 1

Views: 984

Answers (1)

ekhumoro
ekhumoro

Reputation: 120608

Here is a simple way to dynamically set the range on a spinbox:

class SpinBoxSpecial(QtGui.QDoubleSpinBox):
    def __init__(self, parent=None):
        super(SpinBoxSpecial, self).__init__(parent)
        self._last = self.value()
        self.valueChanged.connect(self.handleValueChanged)

    def handleValueChanged(self, value):
        try:
            some_complicated_function(float(value))
            print "yup", value
            self._last = value
        except:
            print "nope", value
            if value > self._last:
                self.setMaximum(self._last)
            else:
                self.setMinimum(self._last)

EDIT:

Just realized the above won't work correctly if a value is typed in directly, because it could fix the min/max too early. So maybe this would be better:

    def handleValueChanged(self, value):
        try:
            some_complicated_function(float(value))
            print "yup", value
            self._last = value
        except:
            print "nope", value
            self.setValue(self._last)

Upvotes: 1

Related Questions