k3njiy
k3njiy

Reputation: 151

Trying to check multiple qt radio buttons with python

I need to check multiple radio buttons from a qt ui with python. Up to now we are using something similar to:

if main.ui.radioButton_1.isChecked():
    responses["q1"] = "1"
elif main.ui.radioButton_2.isChecked():
    responses["q1"] = "2"
elif main.ui.radioButton_3.isChecked():
    responses["q1"] = "3"

if main.ui.radioButton_4.isChecked():
    responses["q2"] = "1"
elif main.ui.radioButton_5.isChecked():
    responses["q2"] = "2"
elif main.ui.radioButton_6.isChecked():
    responses["q2"] = "3"
...

Since there are very many buttons and many different categories (q1, q2, ...) I was thinking of optimizing it a bit. So this is what I hoped would work (adopted from How to get the checked radiobutton from a groupbox in pyqt):

for i, button in enumerate(["main.ui.radioButton_" + str(1) for i in range(1, 8)]):
    if button.isChecked():
        responses["q1"] = str(i - 1)

I get why this doesn't work but writing it I hoped it would. So I tried to iterate through the buttons using something similar to (Is there a way to loop through and execute all of the functions in a Python class?):

for idx, name, val in enumerate(main.ui.__dict__.iteritems()):

and then use some modulo 3 and such to assign the results. But that doesn't work either. Not sure if it's because i used __ dict __ or something else. The error I got was:

TypeError: 'QLabel' object is not iterable

Now some people could say that implicit is better that explicit and also because of readability the if elif chain is good the way it is but there are 400+ lines of that. Also after reading this post, Most efficient way of making an if-elif-elif-else statement when the else is done the most?, I thought there must be a better and more efficient way of doing this (see examples 3.py and 4.py of the of the accepted answer). Because I need to check the Boolean value of main.ui.radioButton_1.isChecked() and then assign thevalue according to the Buttons group (q1, q2,...), I haven't managed to implement the solution using dictionaries as described in the post.

Am I stuck with the if elif chain or is there a way to not only reduce the LOC but also make the code more efficient (faster)?

Upvotes: 2

Views: 6391

Answers (2)

Alex
Alex

Reputation: 315

Another way to do it is using signals. If you had lots of radio button in an application, I suspect this kind of approach would be noticeably faster. For example:

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

class MoodExample(QGroupBox):

    def __init__(self):
        super(MoodExample, self).__init__()

        # Create an array of radio buttons
        moods = [QRadioButton("Happy"), QRadioButton("Sad"), QRadioButton("Angry")]

        # Set a radio button to be checked by default
        moods[0].setChecked(True)   

        # Radio buttons usually are in a vertical layout   
        button_layout = QVBoxLayout()

        # Create a button group for radio buttons
        self.mood_button_group = QButtonGroup()

        for i in xrange(len(moods)):
            # Add each radio button to the button layout
            button_layout.addWidget(moods[i])
            # Add each radio button to the button group & give it an ID of i
            self.mood_button_group.addButton(moods[i], i)
            # Connect each radio button to a method to run when it's clicked
            self.connect(moods[i], SIGNAL("clicked()"), self.radio_button_clicked)

        # Set the layout of the group box to the button layout
        self.setLayout(button_layout)

    #Print out the ID & text of the checked radio button
    def radio_button_clicked(self):
        print(self.mood_button_group.checkedId())
        print(self.mood_button_group.checkedButton().text())

app = QApplication(sys.argv)
mood_example = MoodExample()
mood_example.show()
sys.exit(app.exec_())

I found more information at:

http://codeprogress.com/python/libraries/pyqt/showPyQTExample.php?index=387&key=QButtonGroupClick

http://www.pythonschool.net/pyqt/radio-button-widget/

Upvotes: 1

ekhumoro
ekhumoro

Reputation: 120608

It looks like you have used Qt Designer to create your ui, so I would suggest putting each set of radio buttons in a QButtonGroup. This will give you a simple, ready-made API for getting the checked button in a group without having to query each button individually.

In Qt Designer, buttons can be added to a button-group by selecting them, and then choosing Assign to button group > New button group from the context menu. The button IDs (which you will need to use later) are assigned in the order the buttons are selected. So use Ctrl+Click to select each button of a group in the correct order. The IDs start at 1 for each group and just increase by one for each button that is added to that group.

When a new button-group is added, it will appear in the Object Inspector. This will allow you to select it and give it a more meaningful name.

Once you've created all the groups, you can get the checked button of a group like this:

    responses["q1"] = str(main.ui.groupQ1.checkedId())
    responses["q2"] = str(main.ui.groupQ2.checkedId())
    # etc...

This could be simplified even further to process all the groups in a loop:

    for index in range(1, 10):
        key = 'q%d' % index
        group = 'groupQ%d' % index
        responses[key] = str(getattr(main.ui, group).checkedId())

Upvotes: 3

Related Questions