0

I have written a simple program which creates maths multiplication problems. I wrote it as a CLI, however moved over to a GUI as some teachers were saying that the CLI was too small for pupils to see.

Everything works bar one thing. Once the 'start' button has been clicked I would like to update the listbox on the left with a new question after 5 seconds. In the CLI version I simply added sleep(5) which paused the program and then resumed, however the GUI halts the whole program and waits, then spits out all the questions.

If I remove the for loop the teacher can click the button 15 times, but this seems wasteful.

Here's my code:

from tkinter import *                
from tkinter import messagebox          
from time import sleep                  
from random import randint

questionList=[]

def main():
    for i in range (15):
        num1= randint(0,12)
        num2 = randint(1,12)
        question = ("Question",(i+1),")",num1,"X",num2)
        listbox.insert(END, question)
        #sleep(5)
        tempArray = []
        tempArray.append(num1)
        tempArray.append(num2)
        questionList.append(tempArray)

def answers ():
    for i in range (len(questionList)):
            ans = (questionList[i][0]*questionList[i][1])
            listbox1.insert(END,ans)

root = Tk()                                                                                         
root.geometry("445x590+460+70")                                                                    
root.title("Maths Machine")                                                                         
label = Label(root, text="Maths Machine", font = ("Arial",16)).grid(row = 0, columnspan = 2)
startButton = Button(root, text = "Start", width = 15, command = main).grid(row = 1, column = 1,padx = 10, pady = 10)
label = Label(root, text = "Questions", font = ("Arial",12)).grid(row  = 2, column = 0)
label = Label(root, text = "Answers", font = ("Arial",12)).grid(row  = 2, column = 1)
listbox = Listbox(root, width = 25, height = 15,font = ("Arial",16))
listbox.grid(row = 3, column = 0)
listbox1 = Listbox(root, width = 10, height = 15,font = ("Arial",16))
listbox1.grid(row = 3, column = 1)
answerButton = Button(root, text ="Show answers", width = 15, command = answers).grid(row = 4, column = 1, padx =10, pady =10)


mainloop()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
Neos Nokia
  • 125
  • 1
  • 2
  • 11
  • See how to create a [mcve]. – Peter Wood Sep 28 '18 at 20:54
  • @PeterWood ... what do you mean? – Neos Nokia Sep 28 '18 at 22:11
  • the sleep() function in your case runs in your GUI's main thread, which will block all other actions in your main thread (i.e. button clicks, text updates, basically everything). I think that the root.after() method will be what you're looking for, check out the 'after' method at this link: http://effbot.org/tkinterbook/widget.htm – Erik Sep 28 '18 at 23:44
  • @Erik thank you for this. I have managed to get it to come up one by one, however, it just doesn't stop. Any idea? – Neos Nokia Sep 29 '18 at 14:42
  • @NeosNokia in the function that is being called by the 'after' function, you could just add a simple 'if foo == True:" before the logic in there. Then just change the foo variable to False whenever you don't want that code to be executed. Or maybe it's possible to stop the 'after' function completely, check out [these answers](https://stackoverflow.com/questions/9776718/how-do-i-stop-tkinter-after-function) – Erik Sep 30 '18 at 18:31

2 Answers2

0

This is what I have done to stop my program running and still keep the pause.

count=listbox.size()

count+=1
num1= randint(0,12)
num2 = randint(1,12)
question = ("Q",count,")",num1,"X",num2)
listbox.insert(END, question)
tempArray = []
tempArray.append(num1)
tempArray.append(num2)
questionList.append(tempArray)
winsound.Beep(700,1000)
if notWindows == False:
    w=root.after(5000,main)
if listbox.size() == 15:
    root.after_cancel(w)
    answerButton = Button(root, text ="Show answers", width = 15, command = answers).grid(row = 4, column = 1, padx =10, pady =10)
Neos Nokia
  • 125
  • 1
  • 2
  • 11
0

To update listbox items after a wail you can use after method of the Tk class.

You need to recall the main method after 5 seconds.

def main():
    num1= randint(0,12)
    num2 = randint(1,12)
    question = ("Question",(len(questionList)+1),")",num1,"X",num2)
    listbox.insert(END, question)
    tempArray = []
    tempArray.append(num1)
    tempArray.append(num2)
    questionList.append(tempArray)
    if len(questionList) < 15:
        root.after(5000, main)
Kenly
  • 24,317
  • 7
  • 44
  • 60
  • Thank you for this. This is what I had initially, however , I needed it to end after 15 questions, therefore I added the count which will cancel after 15 loops. – Neos Nokia Oct 11 '18 at 12:39