Entirety of my code is here.
Using tkinter's canvas, I am trying to create a small game that allows people to practice learning the notes on the treble clef.
A random note is initially displayed and the user must select the correct note. I am unable to edit the canvas to display a new note's image if the student got the correct answer.
Can somebody please explain what the problem is with my code?
while True:
randomNote = randint(0, 11)
path = noteFiles[randomNote]
correctNote = notes[randomNote]
img = Image.open(path)
tk_img = ImageTk.PhotoImage(img)
canvas.create_image(505, 200, image=tk_img)
root.mainloop()
if correctNote == noteChosen:
''' User got last note right '''
canvas.delete("all")
GUI programs work completely different from normal Python scripts.
GUI's generally run in an event loop, processing mouse clicks, keys being pressed and other synthetic events. In tkinter this is the
mainloop()
. All code that is executed before the main loop is setup code.When the main loop is running, the only pieces of your code that are actually run are callback functions that you have defined and attached to e.g. button presses and other events.
So attach a callback to the buttons. In that callback, compare the chosen note to the shown one. If correct, update the canvas. If not correct, maybe show a message box.
Note that when your callback is being run, it interrupts the processing of the events in the event loop. So your callbacks should finish quickly. If you need to perform a long-running calculation you could chop it up into little pieces and execute those in a timeout event handler (called
after
in tkinter) or you could start it in a separate process using amultiprocessing.Process
. For technical reasons, usingthreading
for long-running computations does not work well in CPython.Looking at the code you posted, instead of creating all the buttons individually, you create them in aloop. And I would suggest to use
pack
or (preferably)grid
to place buttons instead of using absolute placement.Run the code below and try to understand what it does and how. It displays a random "note" out of five again and again when you press the button for the note displayed (else it prints the bad chosen note and waits until you get it right). I suppose that this is what you need. Your own scripting attempt shows that you have to put some work into your understanding of the basic mechanisms behind tkinter. Read the comments for hints what was wrong with your own coding attempt.
Notice the you have to extend the dictionaries yourself to have the full range of notes covered by the buttons.
The "hidden" feature is that you can switch with the right arrow key to the next note if you don't like the one displayed :D .
ADDENDUM: The next thing to implement in this program is to let the displayed note play if the right one button is pressed.