Improving the Radiobuttons in Python Qt5

Improving the Radiobuttons in Python Qt5

PyQt5 is an alternative GUI interface for Python that you can use instead of Tkinter. Both systems provide ways to create buttons, listboxes, tables, checkboxes and radiobuttons. PyQt5 has a number of advantages, though, including built-in Tooltips. Coding for PyQt is in general as easy or easier than for tkinter, but there are some quirks.

One place where you might find it more troublesome is in the way that it handles Radiobuttons. So, in this article, we show you how to make the QRadioButton class a little friendlier.

Now, the idea of a Radiobutton is that you can only select one button, just like old car radios. This interface is now displayed on some screen in your car, rather than by actual push buttons. But the idea is that if you pick one, any other selected button is unselected.

If you have more than one group of Radiobuttons on a page, you want to find a way to group them so that clicking on a member of one group doesn’t affect the other group. In Tkinter, you do this by associating all the members of one group with a single external variable. Then, whatever button you click changes the value of that variable. So, if you have three buttons, the variable might take on the value 0, 1 or 2.

In Qt5, you group the variables by putting them inside a frame or Groupbox. And how do you find out which on was clicked? You have to run through them all to look for which one’s isChecked() status is true. Now, if there are only two buttons this is simple: you only need to check one button. If its status is false, then the other one must be true. 

But what if you have six or more buttons like in this interface for storing cast members in an operetta?

Figure 1: Six radio buttons used in generating a cast table.

In the tkinter approach, you just take the value of that external variable. In PyQt5, you would have to run through them individually or put them in an array (or List) and run through that.

But here is where we have a cooler solution. The QRadioButton is a first class object and you can create derived classes from it really easily. So, all we need to do, is create a RlRadioButton derived from QRadiobutton which contains an index value for each instance of the button. So, we could write

Lead = RlRadioButton(“Lead”, 0)
MinorLead = RlRadioButton(“Minor lead”, 1)

And so forth.  We can then keep the index of the each button in an instance variable: self.index.

class RlRadioButton(QRadioButton):|
    clickIndex = 0    # key of last button selected stored here

    def __init__(self, label, index):
        super().__init__(label)
        self.index= index

Note that the variable clickIndex is a class-level variable There is only one copy of this variable, shared by all six instances of the RlRadioButton class. But how does this variable get set?

It gets set when you click on that RadioButton. We connect the click event for each button to the same method within the button class.

self.toggled.connect(self.onClicked) #connect click to onClicked

The toggled event occurs whenever you click on a button. The event occurs on the button you click on AND on the button which becomes deselected. So, you must check to see whether the button is selected. If it is selected, this method copies the index of that button in that instance into the class variable clickIndex.

#store index of selected button in class variable
def onClicked(self):
    radio = self.sender()
    if radio.isChecked():   #if it is checked, store that index
       
RlRadioButton.clickIndex = radio.getIndex()

So, what is happening is that there are six instances of RlRadiobutton, one for each button. Each instance has a different index number, and if the button for that instance is clicked, it copies its index into the class variable clickIndex they all hold in common. Then, to find out which was selected you simply check the variable RlRadioButton.clickIndex from anywhere in the program.

We illustrate these instances of the RlRadioButton in Figure 2 below, where button 1 was selected.

Figure 2: Three instances of the RlRadioBtton class, showing that they all have access to the same clickIndex class variable.

This shows that while there are three instances of RlRadioButton with three different indexes, there is only one copy of clickIndex that all instances of the RlRadioButton class share.

In Figure 1, you can click on the Status button to see which Radiobutton was selected. The program then fetches that value from RlRadioButton.clickIndex and displays it in a message box using this somewhat verbose message box code:

msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setText("Role index: "
        + str(RlRadioButton.clickIndex))
msg.setWindowTitle("Status")
msg.setStandardButtons(QMessageBox.Ok )
retval = msg.exec_()

and displays the result in that message box.

Figure 3: The status message box.

So, to conclude, the best way to query a large list of QRadioButtons is by deriving a class which can save the current index and asking the class for the index of the last selected button.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s