Search code examples
pythonrandompyqtqradiobutton

How to randomize the order of radio buttons in pyqt


im making a quiz and i want the radiobuttons to be in different positions. ive got it working to a extent as it would be in random order in the first question however it would then stay in that order for the rest of the quiz. I want it to randomize every time.

class MultipleChoice(QtGui.QWidget):
showTopicsSignal = pyqtSignal()

def __init__(self,parent=None):
    super(MultipleChoice, self).__init__(parent)

    self.initUI()


def initUI(self):
    self.Questions=[]
    self.Questionum = QLabel()
    self.Questioninfo = QLabel()
    self.Correctanswer = QRadioButton()
    self.Incorrectans1 = QRadioButton()
    self.Incorrectans2 = QRadioButton()
    self.Incorrectans3 = QRadioButton()
    self.Correctanswer.setAutoExclusive(True)
    self.Incorrectans1.setAutoExclusive(True)
    self.Incorrectans2.setAutoExclusive(True)
    self.Incorrectans3.setAutoExclusive(True)
    layout = QVBoxLayout(self)
    layout.addWidget(self.Questionum)
    layout.addWidget(self.Questioninfo)
    randomnumber = randint(0,3)
    if randomnumber == 0:
        layout.addWidget(self.Correctanswer)
        layout.addWidget(self.Incorrectans1)
        layout.addWidget(self.Incorrectans2)
        layout.addWidget(self.Incorrectans3)
    elif randomnumber == 1:
        layout.addWidget(self.Incorrectans1)
        layout.addWidget(self.Correctanswer)
        layout.addWidget(self.Incorrectans2)
        layout.addWidget(self.Incorrectans3)
    elif randomnumber == 2:
        layout.addWidget(self.Incorrectans1)         
        layout.addWidget(self.Incorrectans2)
        layout.addWidget(self.Correctanswer)
        layout.addWidget(self.Incorrectans3)
    elif randomnumber == 3:
        layout.addWidget(self.Incorrectans1)         
        layout.addWidget(self.Incorrectans2)
        layout.addWidget(self.Incorrectans3)
        layout.addWidget(self.Correctanswer) 

Solution

  • If you load your answer choices into a container, you can use Python's random (link) library with one or both of the following tools:

    • random.choice(seq) (link) which makes a random choice of the possible items provided in seq
    • random.sample(pop, k) (link) which choice k unique elements from the possible choices provided in pop, without replacing, which I think is key in your situation because you don't want to have the same answer displayed twice on the same question.

    This would simplify your current if-statement block, from

    if randomnumber == 0:
        layout.addWidget(self.Correctanswer)
        layout.addWidget(self.Incorrectans1)
        layout.addWidget(self.Incorrectans2)
        layout.addWidget(self.Incorrectans3)
    

    to

    choices = [self.Correctanswer, self.Incorrectans1, self.Incorrectans2, self.Incorrectans3]
    for q in range(4):
        layout.addWidget(random.sample(choices, 1))
    

    Also just thought of another cool idea. If you have a large "pool" of possible incorrect answers, you can define a function specifically to provide a random selection of wrong answers. Something like:

    def provideWrongAnswers(self, number):
        return random.sample(self.allWrongAnswersPool, number)
    

    which would provide you with number incorrect answers to add to the layout along with the correct.

    In [7]: choices = range(1,11)
    In [9]: random.sample(choices, 3)  # returns a different order of choices each time
    Out[9]: [1, 7, 3]
    In [10]: random.sample(choices, 3)
    Out[10]: [6, 9, 3]
    In [11]: random.sample(choices, 3)
    Out[11]: [5, 4, 2]
    In [12]: random.sample(choices, 3)
    Out[12]: [3, 6, 1]
    In [13]: random.sample(choices, 3)
    Out[13]: [10, 8, 3]
    In [14]: random.sample(choices, 3)
    Out[14]: [1, 7, 2]
    In [15]: random.sample(choices, 3)
    Out[15]: [9, 7, 3]
    

    Finally, random.shuffle(x) (link) be another method, as it takes the sequence x and mixes them up in place. So you could combine the random.sample(wrongChoices, 3) idea which gives you three random incorrect answers, then add in the correct answer and to make sure the correct answer isn't always at the bottom, give em a final stir with random.shuffle(allAnswerChoices)