Kakashi
Kakashi

Reputation: 355

Fix values that are typed into a doublespinbox in PyQt

I want to create a doublespin box that changes values in steps of 0.2. But when the user enters a value that is not correct according to the steps. I normalizes that to the nearest correct value. I tried something like the code shown below but I don't know how to stop values like 0.5 to be entered. Please help me on this.


    from PyQt4.QtCore import *
    from PyQt4.QtGui import *

    class SigSlot(QWidget):
        def __init__(self, parent=None):
            QWidget.__init__(self, parent)
            self.setWindowTitle('spinbox value')
            self.resize(250,150)
            self.lcd1 = QLCDNumber(self)
            self.spinbox1 = QDoubleSpinBox(self)
            self.spinbox1.setSingleStep(0.2)
            self.spinbox1.setCorrectionMode(1)
             # create a Grid Layout
            grid = QGridLayout()
            grid.addWidget(self.lcd1, 0, 0)
            grid.addWidget(self.spinbox1, 1, 0)
            self.setLayout(grid)
             # allows access to the spinbox value as it changes
            self.connect(self.spinbox1, SIGNAL('valueChanged(double)'), self.change_value1)

        def change_value1(self, event):
            val = self.spinbox1.value()
            self.lcd1.display(val)

    app = QApplication([])
    qb = SigSlot()
    qb.show()
    app.exec_()

Upvotes: 2

Views: 3316

Answers (2)

Avaris
Avaris

Reputation: 36715

You have two choices:

  • You can subclass the QSpinBox, override validate method and use an appropriate Q*Validator (e.g. QRegExpValidator) inside.
  • You can check the value in slot connected to valueChanged before using and correct it if necessary.

Since you are already using the valueChanged signal, second option should be fairly easy to implement. Just change your change_value method like this:

def change_value1(self, val): # new value is passed as an argument
    # so no need for this
    # val = self.spinbox1.value()

    new_val = round(val*5)/5 # one way to fix
    if val != new_val:       # if value is changed, put it in the spinbox
        self.spinbox1.setValue(new_val)

    self.lcd1.display(new_val)

By the way, since you are using only one decimal precision, it might be logical to also use:

self.spinbox1.setDecimals(1)

in your __init__. And try to use the new style signals and slots. i.e.:

self.connect(self.spinbox1, SIGNAL('valueChanged(double)'), self.change_value1)

could be written as:

self.spinbox1.valueChanged[float].connect(self.change_value1)

Edit

Subclassing:

class MySpinBox(QDoubleSpinBox):
    def __init__(self, parent=None):
        super(MySpinBox, self).__init__(parent)
        # any RegExp that matches the allowed input
        self.validator = QRegExpValidator(QRegExp("\\d+[\\.]{0,1}[02468]{0,1}"), self)

    def validate(self, text, pos):
        # this decides if the entered value should be accepted
        return self.validator.validate(text, pos)

then instead of using QDoubleSpinBox you would use MySpinBox and leave the input checking to this class.

Upvotes: 5

Jeff
Jeff

Reputation: 7210

In your change value method you can do something like this

val = round(self.spinbox1.value(), 1)
if val/2*10 - int(val/2*10):
    val = round(val, 1) + .1

It's probably not the best way but it works.

Upvotes: 0

Related Questions