在while循环中更改tkinter画布中的图像

时间:2017-04-29 02:05:38

标签: python python-3.x tkinter python-imaging-library tkinter-canvas

我的代码的全部内容是here

使用tkinter的画布,我正在尝试创建一个小游戏,让人们练习学习高音谱号上的音符。

最初显示随机音符,用户必须选择正确的音符。如果学生得到正确答案,我无法编辑画布以显示新笔记的图像。

有人可以解释我的代码有什么问题吗?

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")

2 个答案:

答案 0 :(得分:2)

运行下面的代码并尝试了解它的作用和方式。它显示一个随机的"注意"当你按下按钮显示所显示的音符时,一次又一次地重复五次(否则它会输出错误选择的音符并等待直到你正确)。我想这就是你需要的。您自己的脚本尝试表明您必须在理解tkinter背后的基本机制方面付出一些努力。阅读注释,了解您自己编码尝试的错误。

请注意,您必须自己扩展字典,以便按钮覆盖所有笔记。

"隐藏"功能是你可以用右箭头键切换到下一个音符,如果你不喜欢显示的那个:D。

from random import randint
from tkinter import *
import tkinter as tk
from PIL import ImageTk, Image

root = Tk()
root.wm_attributes("-topmost", 1)
root.geometry('{}x{}'.format(1100, 720)) # window size
# canvas = Canvas(root, bd=0, highlightthickness=0)
canvas = Canvas(root, width=950, height=700)
# canvas.pack()

def client_exit():
    ''' Quit Button '''
    exit()

def pickNote(value):
    ''' Changes noteChosen var to the note's button pressed '''
    global correctNote
    noteChosen = value 
    if noteChosen == correctNote:
        print("SUCCESS !!!")
        displayRandomNote(None)
    else:
        print( " :( ", noteChosen, " :( ")

# Creates button to exit the program
quitButton = tk.Button(text="Quit", command=client_exit)
quitButton.place(x=480, y=480)

# Creates buttons for various notes
aButton = tk.Button(text="A", command=lambda *args: pickNote("A"))
aButton.config(height=3, width=9)
aButton.place(x=190, y=400)

bButton = tk.Button(text="B", command=lambda *args: pickNote("B"))
bButton.config(height=3, width=9)
bButton.place(x=280, y=400)

cButton = tk.Button(text="C", command=lambda *args: pickNote("C"))
cButton.config(height=3, width=9)
cButton.place(x=370, y=400)

dButton = tk.Button(text="D", command=lambda *args: pickNote("D"))
dButton.config(height=3, width=9)
dButton.place(x=460, y=400)

eButton = tk.Button(text="E", command=lambda *args: pickNote("E"))
eButton.config(height=3, width=9)
eButton.place(x=550, y=400)

fButton = tk.Button(text="F", command=lambda *args: pickNote("F"))
fButton.config(height=3, width=9)
fButton.place(x=640, y=400)

gButton = tk.Button(text="G", command=lambda *args: pickNote("G"))
gButton.config(height=3, width=9)
gButton.place(x=730, y=400)

noteFiles = { 1:'1.png', 2:'2.png',  3:'3.png', 4:'4.png', 5:'5.png' } 
notes     = { 1:'A'    , 2:'B'    ,  3:'C'    , 4:'D'    , 5:'E'     } 

randomNote    = randint(1, 5)
path          = noteFiles[randomNote]
correctNote   = notes[randomNote]
img           = Image.open(path)
tk_img        = ImageTk.PhotoImage(img)
imageOnCanvas = canvas.create_image(130, 150, image=tk_img) # position of image center in window
canvas.pack()

def displayRandomNote(event):

    global canvas
    global imageOnCanvas
    global tk_img
    global correctNote
    global notes
    randomNote  = randint(1, 5)
    path        = noteFiles[randomNote]
    correctNote = notes[randomNote]
    img         = Image.open(path)
    tk_img      = ImageTk.PhotoImage(img)
    canvas.itemconfig(imageOnCanvas, image=tk_img) # change the displayed picture
    canvas.pack()

    # userResponse = input("Which note?\n           ")
    # if userResponse == correctNote:
    #     print("                      SUCCESS :) !!!")
    #     print("(switch focus)")
    # else:
    #     print("                      TRY ANOTHER ONE ...")
    #     print("(switch focus)")

# print("Switch window focus to CONSOLE to input the answer. ")
# print("Swicht window focus to IMAGE (press right arrow key for a Note)")

root.bind('<Right>', displayRandomNote) # on right arrow key display random note

root.mainloop()

ADDENDUM:在此程序中要实现的下一件事是,如果按下正确的一个按钮,则会显示所显示的音符。

1.png 2.png 3.png 4.png 5.png

答案 1 :(得分:1)

GUI程序与普通Python脚本完全不同

GUI通常在事件循环中运行,处理鼠标点击,按下键和其他合成事件。在tkinter中,这是mainloop()。在主循环之前执行的所有代码都是设置代码。

当主循环运行时,实际运行的代码的唯一部分是回调函数,这些函数已定义并附加到例如按钮和其他事件。

所以附加一个回调按钮。在该回调中,将所选音符与显示的音符进行比较。如果正确,请更新画布。如果不正确,可能会显示一个消息框。

请注意,在运行回调时,会中断事件循环中事件的处理。所以你的回调应该很快完成。如果你需要执行一个长时间运行的计算,你可以将它切成小块并在超时事件处理程序(在tkinter中称为after)中执行它们,或者你可以使用{{1在一个单独的进程中启动它}}。由于技术原因,使用multiprocessing.Process进行长时间运行的计算 在CPython中运行良好。

查看您发布的代码,而不是单独创建所有按钮,您可以在aloop中创建它们。我建议使用threading或(最好)pack来放置按钮,而不是使用绝对位置。