【问题标题】:Changing image in tkinter canvas in while loop在while循环中更改tkinter画布中的图像
【发布时间】:2017-09-27 05:10:28
【问题描述】:

我的整个代码是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")

【问题讨论】:

  • 在调用mainloop() 之后的任何代码都不会执行,直到您的程序退出(如果有的话)。您需要安排在循环期间 执行您的代码- 键绑定、按钮上的command= 选项或各种其他方式。你没有提供足够的细节来说明你的程序应该如何工作以获得特定的答案。
  • 我对这些东西有点陌生,所以我真的不知道该说什么,但如有必要,我可以提供其余的代码。没那么长。
  • Tkinter 和 while True 循环相处得不好..
  • 如果您对我提供的代码的详细信息有任何疑问,请随时向他们提问。您的代码中有很多问题需要解决,因此解释将导致编写一个 tkinter 教程......希望有一段代码可以根据您的需要工作,您可以继续您的进步并自己制定更多细节。跨度>

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


【解决方案1】:

运行下面的代码并尝试了解它的作用和方式。当您按下显示的音符的按钮时,它会一次又一次地显示五个随机“音符”(否则它会打印错误选择的音符并等到您正确为止)。我想这就是你需要的。您自己的脚本尝试表明您必须在理解 tkinter 背后的基本机制方面做一些工作。阅读 cmets 以了解您自己的编码尝试有什么问题。

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

“隐藏”功能是,如果您不喜欢显示的音符,可以使用右箭头键切换到下一个音符 :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()

附录:在这个程序中要实现的下一件事是,如果按下右一个按钮,则让显示的音符播放。

【讨论】:

  • 我设法整合了你所说的内容,但我唯一不能做的就是有办法检查你选择的笔记是否是正确的答案。我试图在 displayRandomNote 函数中实现它,但无法实现。
  • 我曾尝试使用输入,但我会再试一次。为什么根据用户按下的按钮改变noteChosen变量不足以满足用户输入?
  • 它在一定程度上起作用。它不显示任何错误消息,但是当我输入正确的注释时,它不会像应有的那样打印“成功”。如果可能的话,我仍然想在我的原始代码中加入按钮。我开始认为这个项目有点超出我的想象,因为我在编程方面很烂,哈哈
【解决方案2】:

GUI 程序的工作方式与普通 Python 脚本完全不同

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多