0

I'm looking for a more pythonic way to connect callback functions to multiple sliders on a PyQt based GUI that I am writing. There has to be a better way to do this! On a related note, is there a way to use dictionaries to iteratively call methods on objects? Say if I want to iteratively get the value of each slider? Thanks in advance.

Code that I want to condense (and pythonify!):

    self.ui.seg1Slider.valueChanged.connect(lambda value,segment='1': self.sliderMoved(value,segment))
    self.ui.seg2Slider.valueChanged.connect(lambda value,segment='2': self.sliderMoved(value,segment))
    self.ui.seg3Slider.valueChanged.connect(lambda value,segment='3': self.sliderMoved(value,segment))
    self.ui.seg4Slider.valueChanged.connect(lambda value,segment='4': self.sliderMoved(value,segment))
    self.ui.seg5Slider.valueChanged.connect(lambda value,segment='5': self.sliderMoved(value,segment))
    self.ui.seg6Slider.valueChanged.connect(lambda value,segment='6': self.sliderMoved(value,segment))
    self.ui.seg7Slider.valueChanged.connect(lambda value,segment='7': self.sliderMoved(value,segment))
    self.ui.seg8Slider.valueChanged.connect(lambda value,segment='8': self.sliderMoved(value,segment))
    self.ui.seg10Slider.valueChanged.connect(lambda value,segment='10': self.sliderMoved(value,segment))
    self.ui.seg11Slider.valueChanged.connect(lambda value,segment='11': self.sliderMoved(value,segment))
    self.ui.seg12Slider.valueChanged.connect(lambda value,segment='12': self.sliderMoved(value,segment))
    self.ui.seg13Slider.valueChanged.connect(lambda value,segment='13': self.sliderMoved(value,segment))
    self.ui.seg14Slider.valueChanged.connect(lambda value,segment='14': self.sliderMoved(value,segment))
    self.ui.seg15Slider.valueChanged.connect(lambda value,segment='15': self.sliderMoved(value,segment))
    self.ui.seg17Slider.valueChanged.connect(lambda value,segment='17': self.sliderMoved(value,segment))
    self.ui.seg18Slider.valueChanged.connect(lambda value,segment='18': self.sliderMoved(value,segment))
    self.ui.seg19Slider.valueChanged.connect(lambda value,segment='19': self.sliderMoved(value,segment))
    self.ui.seg20Slider.valueChanged.connect(lambda value,segment='20': self.sliderMoved(value,segment))
    self.ui.seg21Slider.valueChanged.connect(lambda value,segment='21': self.sliderMoved(value,segment))
    self.ui.seg22Slider.valueChanged.connect(lambda value,segment='22': self.sliderMoved(value,segment))
    self.ui.seg23Slider.valueChanged.connect(lambda value,segment='23': self.sliderMoved(value,segment))
    self.ui.seg24Slider.valueChanged.connect(lambda value,segment='24': self.sliderMoved(value,segment))
    self.ui.seg25Slider.valueChanged.connect(lambda value,segment='25': self.sliderMoved(value,segment))
    self.ui.seg26Slider.valueChanged.connect(lambda value,segment='26': self.sliderMoved(value,segment))
    self.ui.seg27Slider.valueChanged.connect(lambda value,segment='27': self.sliderMoved(value,segment))
    self.ui.seg28Slider.valueChanged.connect(lambda value,segment='28': self.sliderMoved(value,segment))
    self.ui.seg29Slider.valueChanged.connect(lambda value,segment='29': self.sliderMoved(value,segment))
    self.ui.seg30Slider.valueChanged.connect(lambda value,segment='30': self.sliderMoved(value,segment))
    self.ui.seg31Slider.valueChanged.connect(lambda value,segment='31': self.sliderMoved(value,segment))
    self.ui.seg32Slider.valueChanged.connect(lambda value,segment='32': self.sliderMoved(value,segment))
crownjbl
  • 43
  • 7
  • 1
    `for i in range(1, 33)`, then `segment = str(i)`. Have you try that? – Clodion Jul 28 '15 at 18:18
  • 1
    Working code that you'd like to clean up probably belongs on [Code Review](http://codereview.stackexchange.com/). – TigerhawkT3 Jul 28 '15 at 18:18
  • I need to connect each individual slider to a function to send values to hardware, so a simple for loop won't work for running methods on objects with similar names (I think). Tigerhawk- fair point, but I feel as though there could be some interesting answers to this question that might benefit others (and illuminate ways to iteratively call methods). – crownjbl Jul 28 '15 at 18:32
  • Using this ... http://stackoverflow.com/questions/3061/calling-a-function-of-a-module-from-a-string-with-the-functions-name-in-python In a loop, concatenate "seg", the number, and "Slider" for the method name. – jcfollower Jul 28 '15 at 20:20

1 Answers1

1

A loop with getattr will work, but it seems you don't have a complete range of numbers to work with (9 and 16 are missing), so you need to take account of that as well:

for segment in range(1, 33):
    if segment == 9 or segment == 16:
        continue
    slider = getattr(self.ui, 'seg%dSlider' % segment)
    slider.valueChanged.connect(
        lambda value, segment=str(segment): self.sliderMoved(value, segment))

However, a somewhat cleaner solution may be possible, since it looks like you are using Qt Designer to create the GUI. This means that the sliders will all get object names that match their attribute names. If you also make sure that all the sliders are put inside a container widget, you will then be able to do something like this:

for slider in self.ui.sliderContainer.findChildren(QtGui.QSlider):
    segment = slider.objectName()[3:][:-6]
    slider.valueChanged.connect(
        lambda value, segment=segment: self.sliderMoved(value, segment))

This is much more robust than the previous solution, because as long as you use the same naming format, you can safely add or remove sliders in Qt Designer without needing to update this code as well.

(PS: It's also possible to find children with object-names that match a given QRegExp).

ekhumoro
  • 115,249
  • 20
  • 229
  • 336