Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I'm currently writing some code in PyQt4 that takes a value and a control and binds the value to the control. Once the user save the form it will unbind all the values and save it back to custom object (in this case QgsFeature).

So at the moment I have bind and unbind code which uses if/elif to workout the control type and then use the correct methods to bind the value. Like so:

def bindValueToControl(self, control, value):
        """
        Binds a control to the supplied value.
        Raises BindingError() if control is not supported.

        control - QWidget based control that takes the new value
        value - A QVariant holding the value
        """
        if isinstance(control, QCalendarWidget):
            control.setSelectedDate(QDate.fromString(value.toString(), Qt.ISODate))

        elif isinstance(control, QListWidget):
            items = control.findItems(value.toString(), Qt.MatchExactly)
            try:
                control.setCurrentItem(items[0])
                control.currentItemChanged.emit(None, items[0])
            except IndexError:
                pass

        elif isinstance(control, QLineEdit) or isinstance(control, QTextEdit):
            control.setText(value.toString())

        elif isinstance(control, QCheckBox) or isinstance(control, QGroupBox):
            control.setChecked(value.toBool())

        elif isinstance(control, QPlainTextEdit):
            control.setPlainText(value.toString())

        elif isinstance(control, QComboBox):
            # Add items stored in the database
            query = QSqlQuery()
            query.prepare("SELECT value FROM ComboBoxItems WHERE control = :contorl")
            query.bindValue(":control", control.objectName())
            query.exec_()
            while query.next():
                newvalue = query.value(0).toString()
                if not newvalue.isEmpty():
                    control.addItem(newvalue)

            itemindex = control.findText(value.toString())
            if itemindex == -1:
                control.insertItem(0,value.toString())
                control.setCurrentIndex(0)
            else:
                control.setCurrentIndex(itemindex)

        elif isinstance(control, QDoubleSpinBox):
            double, passed = value.toDouble()
            control.setValue(double)

        elif isinstance(control, QSpinBox):
            integer, passed = value.toInt()
            control.setValue(integer)
        else:
            raise BindingError(control, value.toString(), "Unsupported widget %s" % control)

for unbind:

def unbindFeature(self, qgsfeature):
    """
    Unbinds the feature from the form saving the values back to the QgsFeature.
    """
    for index, control in self.fieldtocontrol.items():
            value = None
            if isinstance(control, QLineEdit):
                value = control.text()

            elif isinstance(control, QTextEdit) or isinstance(control, QPlainTextEdit):
                value = control.toPlainText()

            elif isinstance(control, QCalendarWidget):
                value = control.selectedDate().toString(Qt.ISODate)

            elif isinstance(control, QCheckBox) or isinstance(control, QGroupBox):
                value = 0
                if control.isChecked():
                    value = 1
            elif isinstance(control, QComboBox):
                value = control.currentText()
                if control.isEditable():
                    self.saveComboValues(control, value)

            elif isinstance(control, QDoubleSpinBox) or isinstance(control, QSpinBox):
                value = control.value()

            elif isinstance(control, QDateTimeEdit):
                value = control.dateTime().toString(Qt.ISODate)

            elif isinstance(control, QListWidget):
                item = control.currentItem()
                if item:
                    value = item.text()
                else:
                    return QString("")

I can't help but feel this is a little dirty looking. Is there a nicer, more maintainable, way to handle something like this.

share|improve this question

2 Answers

To expand a little further on part of sky py's answer, you could try something like the following

class BaseControlHandler:
    def __init__( self, control ):
        self.control = control
    def bind( self, value ): 
        raise SuitableException()
    def unbind( self ):
        raise SuitableException()

class LineEditHandler( BaseControlHandler ):
    def __init__( self, control ):
        BaseControlHandler.__init__( self, control )
    def bind( self, value ):
        self.control.setText(value.toString())
    def unbind( self ):
        return self.control.text()

class CheckBoxHandler( BaseContolHandler ):
    # etc

You could then set up a dictionary mapping the control type to the appropriate handler:

handlers = { QtLineEdit: LineEditHandler, QtCheckBox: CheckBoxHandler, ... }

So your main block of if..elif.. becomes

for ctltype in handlers:
    if isinstance( control, ctltype ):
        ctl = handlers[ctltype]( control )
        ctl.bind( value ) # or unbind
        break

You'll unfortunately need to keep the handlers= line and the subclasses in step together.

share|improve this answer

This post might help you Pythonic way to avoid a mountain of if…else statements

The concept of dispatch table is also a good way of handling large if-else or switch block.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.